… and how they might make you sad.
Released: March 1, 2012
EOL: September 14, 2014
End of Support: September 14, 2015
Latest version: 5.4.45 (released September 3, 2015)
Major changes:
User input automatically becomes variables in your script.
No need for $_GET, $_POST, or $_REQUEST.
Where to set:
.htaccess:php_flag register_globals Off
or
php_flag register_globals On
php.ini:register_globals = on
or
register_globals = off
For example:
echo $user_id;
if($is_admin){
echo "You are in, administrator.
}
Output:
$ curl http://quitesecure.com/script.php?user_id=1337&is_admin=true
1337
You are in, administrator.
echo $user_id;
$user_id = $_REQUEST['user_id'];
echo $id;
… or …
$user_id = (isset($_GET['user_id'])) ?
intval($_GET['user_id']) : false;
if ($user_id && $user_id > 0) {
echo $user_id;
} else {
echo "Invalid User ID";
}
Optional setting. It caused many problems.
// Example of magic quotes in action
$username = "O'Reilly";
$query = "SELECT * FROM users WHERE username = '$username'";
echo $query;
// Output with magic quotes enabled:
// SELECT * FROM users WHERE username = 'O\'Reilly'
// Output with magic quotes disabled:
// SELECT * FROM users WHERE username = 'O'Reilly'
$name = $_POST['name'];
$query = "INSERT INTO users (name) VALUES ('" .
mysqli_real_escape_string($conn, $name) . "')";
… or …
// Using MySQLi Object-Oriented with prepared statements
$name = $_POST['name'];
$filteredName = preg_replace(
'/[^a-zA-Z0-9\s\.,-]/', '',
$name);
$stmt = $mysqli->prepare("INSERT INTO users
(name)
VALUES (?);");
$stmt->bind_param("s", $filteredName);
$stmt->execute();
$stmt->close();
$mysqli->close();
Default charset for some functions switched from ISO-8859-1 to UTF-8;
Functions will return an empty string if the content is not valid UTF-8.
You can still pass a specific encoding as the second parameter.
htmlspecialchars()htmlentities()html_entity_decode()htmlspecialchars( $some_data )
… becomes:
htmlspecialchars( $some_data, ENT_COMPAT | ENT_XHTML, 'ISO-8559-1' )
… or, to test 5.4.x behaviour in 5.3.x:
htmlspecialchars( $some_data, ENT_COMPAT | ENT_XHTML, 'UTF-8' )
safe_mode() removed.TZ environment variable; you can use the php.ini setting date.timezone or the date_default_timezone_set function to set the default timezone.function something($_GET) { is no longer valid.Released: June 20, 2013
EOL: July 10, 2015
Latest version: 5.5.38 (released July 21, 2016)
Major changes:
Released: August 28, 2014
EOL: December 31, 2018
Latest version: 5.6.40 (released January 10, 2019)
Major changes:
No changes required if SSL certificates:
Best fix is to fix SSL certificates.
Possible fix is disabling.
Released: December 3, 2015
EOL: January 10, 2019
Latest version: 7.0.33 (released January 10, 2019)
Major changes:
PHP 7.0 introduces a new hierarchy for error handling:
interface Throwable
|- Exception implements Throwable
|- ...
|- Error implements Throwable
|- TypeError extends Error
|- ParseError extends Error
|- ArithmeticError extends Error
|- AssertionError extends Error
All exceptions and errors now implement the Throwable interface.
Example usage:
try {
// Some code that might throw an exception or error
} catch (Exception $e) {
// Handle regular exceptions
} catch (Error $e) {
// Handle PHP errors
} catch (Throwable $e) {
// Handle any throwable not caught by the previous blocks
}
Note: You cannot implement Throwable directly in user code. Use Exception or Error instead.
E_STRICT errors reclassified:
Some converted to E_DEPRECATED or E_NOTICE Most converted to E_WARNING E_STRICT constant remains, but unused
E_STRICT errors reclassified:
Using $this in a static method: E_DEPRECATED
class MyClass {
public static function myStaticMethod() {
echo $this->someProperty;
}
}
Accessing static property non-statically: E_NOTICE
class AnotherClass {
public static $staticProperty = 'Static Value';
}
$instance = new AnotherClass();
echo $instance->staticProperty;
Variables, properties, and methods
Syntax:
$$foo['bar']['baz']
PHP 5.x:
${$foo['bar']['baz']}
PHP 7.x
($$foo)['bar']['baz']
New fatal errors:
Catchable fatal errors now throw TypeError:
The mysql extension has been removed in PHP 7.0.
Replace mysql_* functions with mysqli or PDO_MySQL:
// Old code using mysql_*
$connection = mysql_connect($host, $username, $password);
mysql_select_db($database, $connection);
$result = mysql_query("SELECT * FROM table");
while ($row = mysql_fetch_assoc($result)) {
// Process row
}
mysql_close($connection);
// New code using mysqli
$mysqli = new mysqli($host, $username, $password, $database);
$result = $mysqli->query("SELECT * FROM table");
while ($row = $result->fetch_assoc()) {
// Process row
}
$mysqli->close();
// Or using PDO
$pdo = new PDO("mysql:host=$host;dbname=$database", $username, $password);
$stmt = $pdo->query("SELECT * FROM table");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// Process row
}
$pdo = null;
Released: December 1, 2016
EOL: December 1, 2019
Latest version: 7.1.33 (released October 24, 2019)
Major changes:
<?php
function example_function(...$args) {
$total = 0;
foreach ($args as $arg) {
$total += $arg;
}
return $total;
}
$result1 = example_function(1, 2, 3);
$result2 = example_function(10, 20, 30, 40, 50);
echo "Result 1: " . $result1 . "\n";
echo "Result 2: " . $result2 . "\n";
?>
Results:
Result 1: 6
Result 2: 150
Example:
<?php
function say_hello($tom){ echo "Hi, $tom"; }
say_hello();
?>
Result in PHP 7.1.0:
PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function say_hello(), 0 passed
in Standard input code on line 4 and exactly 1 expected in Standard input code:2
Released: November 30, 2017
EOL: November 30, 2020
Latest version: 7.2.34 (released October 1, 2020)
Major changes:
var_dump(number_format(-0.01)); // now outputs string(1) "0" instead of string(2) "-0"
Before 7.2.0:
string(2) "-0"
7.2.0:
string(1) "0"
Improve SSL/TLS defaults
tls:// now defaults to TLSv1.0 or TLSv1.1 or TLSv1.2
STREAM_CRYPTO_METHOD_TLS_* constants default to TLSv1.0 or TLSv1.1 + TLSv1.2, instead of TLSv1.0 only
Released: December 6, 2018
EOL: December 6, 2021
Latest version: 7.3.33 (released November 18, 2021)
Major changes:
Due to the introduction of flexible heredoc/nowdoc syntax, doc strings that contain the ending label inside their body may cause syntax errors or change in interpretation. For example in:
$xyz = <<<FOO
abcdefg
FOO
FOO;
echo $xyz;
$xyz = <<<ENDDOC
abcdefg
FOO
ENDDOC;
echo $xyz;
Released: November 28, 2019
EOL: November 28, 2022
Latest version: 7.4.33 (released November 3, 2022)
Major changes:
Password hashing algorithm identifiers are now nullable strings rather than integers.
PASSWORD_DEFAULT was int 1; now is string 2y (it was null in PHP 7.4.x)PASSWORD_BCRYPT was int 1; now is string 2yPASSWORD_ARGON2I was int 2; now is string argon2iPASSWORD_ARGON2ID was int 3; now is string argon2idIf you’re not hardcoding or duplicating constants, this shouldn’t effect anything.
fn is now a reserved keyword. It can no longer be used as a function or class name - ithough it can still be used as a method or class constant name.
o serialization format has been removed. This was produced by PHP 3.x, though note that apparently serialization has been broken for a long time.
Released: November 26, 2020
EOL: November 26, 2023
Latest version: 8.0.30 (released August 3, 2023)
Major changes:
| Before | After |
|---|---|
$something{0} |
$something[0] |
$something{'key'} |
$something['key'] |
each($some_array as $v){ ... }
foreach($some_array as $v) { ... }
| Expr | 5.6 | 8.0 |
|---|---|---|
0.0 > '' |
False | True |
0 > '' |
False | True |
0.0 == '' |
True | False |
0 == '' |
True | False |
0.0 != '' |
False | True |
0 != '' |
False | True |
replaced by NumberFormatter::formatCurrency() and NumberFormatter::parseCurrency()
$number = 2345.67;
setlocale(LC_MONETARY, 'en_US');
echo money_format('%i', $number); # => USD 2,345.67
… becomes:
$number = 2345.67;
$formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
echo $formatter->formatCurrency($number, 'USD'); # => USD 2,345.67
Released: November 25, 2021
EOL: December 31, 2026
Latest version: 8.1.29 (released June 6, 2024)
Major changes:
Write access to entire $GLOBALS array disallowed, as in:
array_pop($GLOBALS)
Read access still works.
Write access to individual elements still works:
$GLOBALS['foo'] = 'baz';
Affected functions:
htmlspecialchars()
htmlentities()
htmlspecialchars_decode()
html_entity_decode()
get_html_translation_table()
Default mode is now ENT_QUOTES | ENT_SUBSTITUTE rather than ENT_COMPAT.
Changes:
' is escaped to '.
Malformed UTF-8 will be replaced by a Unicode substitution character, instead of resulting in an empty string.
Released: December 8, 2022
EOL: December 31, 2027
Latest version: 8.2.22 (released August 1, 2024)
Major changes:
String localization Example:
<?php
echo strtoupper("Jäschke");
echo "\n";
echo mb_strtoupper("Jäschke");
?>
Output:
JäSCHKE
JÄSCHKE
strtolower(), strtoupper(), stristr(), stripos(), strripos(), lcfirst(), ucfirst(), ucwords(), and str_ireplace() are longer locale-sensitive.
Literally, this is implemented with subtraction and addition:
"A" (0x41) to "Z" (0x5a)
"a" (0x61) to "z" (0x7a)
strtolower adds 32 to characters in the first range, strtoupper subtracts, etc.
Localized versions of these functions are available in the MBString extension.
Released: November 23, 2023
EOL: December 31, 2026
End of Support: December 31, 2025
Latest version: 8.3.3 (released February 15, 2024)
Major changes:
Some programs very close to stack oveflow may now throw an error.
proc_get_status() bugs fixed.
Numerous DOM extension changes
AST rewriting tools:
PHPStan
Semgrep
rector
others
Tend to produce large diffs.
IDE plugins and extensions
Personal preferred workflow:
LLM-powered tools can be valuable assets in upgrading PHP applications:
Limitations to consider:
Nothing replaces human understanding.
Compatibility layers can help bridge the gap between PHP versions:
Symfony Polyfill
mysql/mysqli
DIY