More Facepalms
The
    (unset) Cast
    This is a fun one. For whatever reasons, probably just because in some way PHP’s grammar allowed it, and just because the compiler would not bail out on it, the following code is valid PHP syntax:
$a = 42;
var_dump($a);
(unset) $a;
var_dump($a);
    Yes, it was possible to cast a value to
    unset. Which is not the same thing as unsetting it,
    because it just returns null. It does not affect the
    original variable, as the output shows:
int(42)
int(42)
    Just for the sake of completeness: if you want to unset a
    variable, use unset():
$a = 42;
var_dump($a);
unset($a);
var_dump($a);
    This will unset the variable as expected:
int(42)
Notice: Undefined variable: a ...
NULL
    Since casting to unset always returns
    null, it is just a very fancy way of writing
    null itself. The whole thing just serves no purpose.
    Thus, as of PHP 7.2, casting to unset has been
    deprecated:
Deprecated: The (unset) cast is deprecated in ...
    If you encounter this error message, fixing up the code is really
    easy. Just remove the cast to unset, as it does not do
    anything anyway.
Deprecated
    ezmlm_hash()
    ezmlm (“eazy mailing list manager”) is a free mailing list software developed in 1997 that has been unmaintained ever since. A fork exists that is named ezmlm-idx, but this has also been unmaintained since 2014.
The function ezmlm_hash() can be used to hash an
    email address. According to the manual this is required when storing
    ezmlm mailing lists in a MySQL database. As of PHP 7.4,
    ezmlm_hash() has been deprecated, so
var_dump(ezmlm_hash('user@example.com'));
    will result in:
PHP Deprecated: Function ezmlm_hash() is deprecated in ...
int(44)
    You are asking why this is a facepalm? Because it breaks encapsulation if you deal with implementation details that should, by definition, be private in the first place. If ezmlm at some point decided to change the way they hash an email address, they would most certainly not be aware of the fact that they would need to tell the PHP project.
Plus, a hash should not be an int, should it?
Nested Ternary Operators Need Parentheses
Computer programs are mainly about loops, and about making
    decisions. We use if statements to make decisions, but
    sometimes, when we feel that the code is too verbose, we might use
    the ternary operator instead:
$a = random_int(0, 10);
if ($a > 5) {
    $result = 'pretty big';
} else {
    $result = 'rather small';
}
    We can shorten this to:
$result = $a > 5 ? 'pretty big' : 'rather small';
    One can argue whether it is worth shortening this if
    statement to one line, since code coverage reporting would show that
    one line as executed, event though there are technically two
    execution paths on this one line, requiring two test cases to be
    fully covered. The more verbose if statement puts execution path on
    a single line, which makes code coverage reporting less
    misleading.
But this is –maybe– besides the point here. How about this piece of code:
$result = $a > 5 ? 'pretty big' : $a < 1 ? 'very small' : 'rather small';
    This line is hard to read. Maybe the ternary operator should just not be nested? Still, nested ternary operators are allowed in PHP. It turns out that PHP interprets nested ternary operators differently, namely left-associative. Most other programming langauge treat it right-associatively, which of course causes a lot of confusion:
$a = 3;
var_dump(
        $a == 1 ? 'one'
        : $a == 2 ? 'two'
        : $a == 3 ? 'three'
        : $a == 4 ? 'four'
        : 'other'
);
    Now, what output would you expect?
string(4) "four"
    That is a surprise, isn’t it? Again, maybe you should not have nested ternary operators in the first place, but since you did, PHP now helps you with a deprecation message:
PHP Deprecated:
Unparenthesized a ? b : c ? d : e is deprecated.
Use either (a ? b : c) ? d : e or a ? b : (c ? d : e) in ...
    Basically this tells you to make the operator precedence explicit:
$a = 3;
var_dump(
       $a == 1 ? 'one'
    : ($a == 2 ? 'two'
    : ($a == 3 ? 'three'
    : ($a == 4 ? 'four'
    : 'other')))
);
    Can we please agree on not using nested ternary operators?
Non-String Arguments to
    mb_ereg_replace()
    When working with strings, using regular expressions to search
    and replace is very common, and sometimes extremely useful. We have
    already mentioned previously that PHP’s built-in string functions do
    a pretty bad job on non-ASCII strings. The mbstring
    extension offers functions that can deal with multibyte strings, for
    example mb_ereg_replace() that can be used to replace
    substrings:
var_dump(mb_ereg_replace('ä', 'ö', 'seriäs'));
    Even though this example does not use a “real” regular
    expression, it does use German umlauts and thus non-ASCII
    characters. To do things properly, we would have to call
    mb_regex_encoding() to define the encoding. But since
    we are in a “facepalm” chapter, we do not need all this to let
    things get weird. What would you expect the following example to
    do:
var_dump(mb_ereg_replace(111, '...', 'some string'));
    Well, let us run the code to find out:
PHP Deprecated:
mb_ereg_replace(): Non-string patterns will be interpreted as strings in the future.
Use an explicit chr() call to preserve the current behavior in ...
string(13) "s...me string"
    PHP treats the integer 111 as the ASCII character o,
    thus replacing it in the original string. Since PHP 7.4, however,
    there is an additional deprecation message which in this case warns
    you of a future change to PHP: probably starting with PHP 8, the
    integer 111 will be interpreted as a string
    '111', which will probably lead to unexpected
    behaviour. But then again, there should really be no reason to pass
    a non-string argument to a function that makes string
    replacements.
Case-Insensitive Constants
Constants are always upper case, right? Well … almost. Turns out
    that in PHP it has always been more of a soft convention that
    constants are upper case. The special constants true,
    false, and null, for example, also exist
    in a lower case version, and in fact most coding standards suggest
    to use them in lower case only.
define('TEST_Constant', 'some-value', true);
var_dump(TEST_CONSTANT);
    This will output:
Warning: Use of undefined constant TEST_CONSTANT - assumed 'TEST_CONSTANT'
(this will throw an Error in a future version of PHP) in ...
string(13) "TEST_CONSTANT"
    This is clearly not case-sensitive, but exposes PHP’s strange
    behaviour of defining constants at runtime. To add even more
    confusion, you can make constants case-insensitive by passing an
    additional parameter to define():
define('TEST_Constant', 'some-value', true);
var_dump(TEST_CONSTANT);
    On older PHP versions, this will result in:
string(10) "some-value"
    Since PHP 7.3, two deprecation warnings will be shown, one when defining a case-insensitive constant
Deprecated:
define():
Declaration of case-insensitive constants is deprecated in ...
Deprecated:
Case-insensitive constants are deprecated.
The correct casing for this constant is "TEST_Constant" in ...
string(10) "some-value"
    In PHP 8, it will not be possible to define case-insensitive constants any more. In addition, PHP 8 will no longer magically define constants at runtime, so all of the above programs will lead to a fatal error on PHP 8.
Bottom line: just always use upper case constants. Start doing so now, if you haven’t already. If you are not convinced yet:
define('constant', 'some-value', true);
var_dump(constant);
var_dump(CONSTANT);
define('CONSTANT', 'some-other-value');
var_dump(constant);
var_dump(CONSTANT);
    Up to PHP 7.2.31, this will output:
string(10) "some-value"
string(10) "some-value"
string(10) "some-value"
string(16) "some-other-value"
    Whoops! Did we just re-define a constant?
Impossible URL Filters
Using the filter extension, input strings can be
    filtered (or validated), for example to find out if a given string
    is a valid URL:
var_dump(filter_var('http://example.com/', FILTER_VALIDATE_URL));
var_dump(filter_var('not-a-url', FILTER_VALIDATE_URL));
    Obviously, the first string is a valid URL, whereas the second one is not:
string(19) "http://example.com/"
bool(false)
    Since PHP 7.3, the two constants
    FILTER_FLAG_SCHEME_REQUIRED and
    FILTER_FLAG_HOST_REQUIRED are deprecated.
var_dump(filter_var('//example.com/', FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED));
var_dump(filter_var('https:///path/', FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED));
    Not only will PHP yell at you, the constants do not serve any purpose since neither the scheme, nor the host can be omitted from the URL:
PHP Deprecated:
filter_var():
explicit use of FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is deprecated in ...
bool(false)
PHP Deprecated:
filter_var():
explicit use of FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED is deprecated in ...
bool(false)
    Since the two constants in question do not serve any purpose,
    they have been deprecated and will be removed in PHP 8. If your
    application is affected it should be safe just to remove the
    constants from the filter_var() call.
Are you Using PDO to Connect to DB2 via ODBC?
This sounds like a pretty edgy edge case already. If you
    additionally use the php.ini setting
    pdo_odbc.db2_instance_name, you will be greeted with a
    deprecation warning starting with PHP 7.3.
The fun fact is that this setting has been marked as deprecated
    in the PHP manual since version 5.1.1. Now the code was adjusted to
    the manual, if you will. The reason for the deprecation is that
    pdo_odbc.db2_instance_name triggered the modification
    of a system environment variable, which could cause undesired side
    effects.