Changeset View
Changeset View
Standalone View
Standalone View
src/docs/flavor/php_pitfalls.diviner
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | If a value is not truthy, it is "falsey". These values are falsey in PHP: | ||||
null // null | null // null | ||||
0 // integer | 0 // integer | ||||
0.0 // float | 0.0 // float | ||||
"0" // string | "0" // string | ||||
"" // empty string | "" // empty string | ||||
false // boolean | false // boolean | ||||
array() // empty array | array() // empty array | ||||
Disregarding some bizarre edge cases, all other values are truthy. Note that | Disregarding some bizarre edge cases, all other values are truthy. | ||||
because "0" is falsey, this sort of thing (intended to prevent users from making | |||||
empty comments) is wrong in PHP: | |||||
COUNTEREXAMPLE | |||||
if ($comment_text) { | |||||
make_comment($comment_text); | |||||
} | |||||
This is wrong because it prevents users from making the comment "0". //THIS | |||||
COMMENT IS TOTALLY AWESOME AND I MAKE IT ALL THE TIME SO YOU HAD BETTER NOT | |||||
BREAK IT!!!// A better test is probably `strlen()`. | |||||
valerio.bozzolan: I moved this text under the section "Check for non-empty strings" | |||||
In addition to truth tests with `if`, PHP has two special truthiness operators | In addition to truth tests with `if`, PHP has two special truthiness operators | ||||
which look like functions but aren't: `empty()` and `isset()`. These operators | which look like functions but aren't: `empty()` and `isset()`. These operators | ||||
help deal with undeclared variables. | help deal with undeclared variables. | ||||
In PHP, there are two major cases where you get undeclared variables -- either | In PHP, there are two major cases where you get undeclared variables -- either | ||||
you directly use a variable without declaring it: | you directly use a variable without declaring it: | ||||
Show All 15 Lines | |||||
When you do either of these, PHP issues a warning. Avoid these warnings by | When you do either of these, PHP issues a warning. Avoid these warnings by | ||||
using `empty()` and `isset()` to do tests that are safe to apply to undeclared | using `empty()` and `isset()` to do tests that are safe to apply to undeclared | ||||
variables. | variables. | ||||
`empty()` evaluates truthiness exactly opposite of `if()`. `isset()` returns | `empty()` evaluates truthiness exactly opposite of `if()`. `isset()` returns | ||||
`true` for everything except `null`. This is the truth table: | `true` for everything except `null`. This is the truth table: | ||||
| Value | `if()` | `empty()` | `isset()` | | | Value | `if()` | `empty()` | `isset()` | | ||||
|-------|--------|-----------|-----------| | |---------------|--------|-----------|-----------| | ||||
| `null` | `false` | `true` | `false` | | | `null` | `false`| `true` | `false` | | ||||
| `0` | `false` | `true` | `true` | | | `0` | `false`| `true` | `true` | | ||||
| `0.0` | `false` | `true` | `true` | | | `0.0` | `false`| `true` | `true` | | ||||
| `"0"` | `false` | `true` | `true` | | | `"0"` | `false`| `true` | `true` | | ||||
| `""` | `false` | `true` | `true` | | | `""` | `false`| `true` | `true` | | ||||
| `false` | `false` | `true` | `true` | | |`false` | `false`| `true` | `true` | | ||||
| `array()` | `false` | `true` | `true` | | |`array()` | `false`| `true` | `true` | | ||||
| Everything else | `true` | `false` | `true` | | |Everything else| `true` | `false` | `true` | | ||||
Done Inline ActionsI just indented a bit valerio.bozzolan: I just indented a bit | |||||
The value of these operators is that they accept undeclared variables and do | The value of these operators is that they accept undeclared variables and do | ||||
not issue a warning. Specifically, if you try to do this you get a warning: | not issue a warning. Specifically, if you try to do this you get a warning: | ||||
```lang=php, COUNTEREXAMPLE | ```lang=php, COUNTEREXAMPLE | ||||
if ($not_previously_declared) { // PHP Notice: Undefined variable! | if ($not_previously_declared) { // PHP Notice: Undefined variable! | ||||
// ... | // ... | ||||
} | } | ||||
Show All 20 Lines | `is_falsey_or_is_not_declared()`. Thus: | ||||
- When you use `isset()` on an array key, like `isset($array['key'])`, it | - When you use `isset()` on an array key, like `isset($array['key'])`, it | ||||
will evaluate to "false" if the key exists but has the value `null`! Test | will evaluate to "false" if the key exists but has the value `null`! Test | ||||
for index existence with `array_key_exists()`. | for index existence with `array_key_exists()`. | ||||
Put another way, use `isset()` if you want to type `if ($value !== null)` but | Put another way, use `isset()` if you want to type `if ($value !== null)` but | ||||
are testing something that may not be declared. Use `empty()` if you want to | are testing something that may not be declared. Use `empty()` if you want to | ||||
type `if (!$value)` but you are testing something that may not be declared. | type `if (!$value)` but you are testing something that may not be declared. | ||||
= Check for non-empty strings = | |||||
As already mentioned, note that you cannot just use an `if` or `empty()` to | |||||
check for a non-empty string, mostly because "0" is falsey, so you cannot rely | |||||
on this sort of thing to prevent users from making empty comments: | |||||
COUNTEREXAMPLE | |||||
if ($comment_text) { | |||||
make_comment($comment_text); | |||||
} | |||||
This is wrong because it prevents users from making the comment "0". | |||||
//THE COMMENT "0" IS TOTALLY AWESOME AND I MAKE IT ALL THE TIME SO YOU HAD | |||||
BETTER NOT BREAK IT!!!// | |||||
Another way //was// also `strlen()`: | |||||
COUNTEREXAMPLE | |||||
if (strlen($comment_text)) { | |||||
make_comment($comment_text); | |||||
} | |||||
Done Inline Actions↑ That part was just copy-pasted mostly from the already-existing block ↓ This part is new valerio.bozzolan: ↑ That part was just copy-pasted mostly from the already-existing block
↓ This part is new | |||||
But using `strlen(null)` causes a deprecation warning since PHP 8.1. Also, | |||||
using `strlen()` uses too many CPU cycles to just check of a non-empty. | |||||
In short, outside Phorge, this is a general way to check for non-empty strings | |||||
for most wild input types: | |||||
```lang=php | |||||
$value_str = (string) $value; | |||||
if ($value_str !== '') { | |||||
// do something | |||||
} | |||||
``` | |||||
To do the same thing in Phorge, use this better and safer approach: | |||||
```lang=php | |||||
$value_str = phutil_string_cast($value); | |||||
if ($value_str !== '') { | |||||
// do something | |||||
} | |||||
``` | |||||
And, if you are 100% sure that you are __only__ working with string and | |||||
null, evaluate this instead: | |||||
```lang=php | |||||
if (phutil_nonempty_string($value)) { | |||||
// do something | |||||
} | |||||
``` | |||||
WARNING: The function `phutil_nonempty_string()` is designed to throw a nice | |||||
exception if it receives `true`, `false`, an array, an object or anything | |||||
alien that is not a string and not null. Do your evaluations. | |||||
= usort(), uksort(), and uasort() are Slow = | = usort(), uksort(), and uasort() are Slow = | ||||
This family of functions is often extremely slow for large datasets. You should | This family of functions is often extremely slow for large datasets. You should | ||||
avoid them if at all possible. Instead, build an array which contains surrogate | avoid them if at all possible. Instead, build an array which contains surrogate | ||||
keys that are naturally sortable with a function that uses native comparison | keys that are naturally sortable with a function that uses native comparison | ||||
(e.g., `sort()`, `asort()`, `ksort()`, or `natcasesort()`). Sort this array | (e.g., `sort()`, `asort()`, `ksort()`, or `natcasesort()`). Sort this array | ||||
instead, and use it to reorder the original array. | instead, and use it to reorder the original array. | ||||
▲ Show 20 Lines • Show All 181 Lines • Show Last 20 Lines |
Content licensed under Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) unless otherwise noted; code licensed under Apache 2.0 or other open source licenses. · CC BY-SA 4.0 · Apache 2.0
I moved this text under the section "Check for non-empty strings"