Despite the fact that we are actively working with Python and Go, still a significant part of our server code is written in PHP. Therefore, we are closely following all the innovations of the language. Less than a year has passed since the release of the previous minor version, and now the last beta release is scheduled for August 17th. It is not recommended to use it in production yet, but you can already download the docker image . It's time to figure out what has changed in the new version of the language.
Opcache adds global optimization based on data flow analysis using SSA (Static single assignment form): Sparse Conditional Constant Propagation (SCCP), dead code elimination (DCE) removal, and deletion of unused local variables.
Optimized the in_array()
built-in function by searching for a hash in an inverted array.
Previously, extension=
and zend_extension=
in the php.ini file contained paths to the extension file.
But, unfortunately, the file name depended on the platform. For example, in unix-like systems, it was built as <extension-name>.<suffix>
, where suffix
is .so
on all systems except HP-UX , where it is sl
. On Windows, the file name is generated as php_<extension-name>.dll
. All this caused a lot of mistakes.
Now you can write:
extension=bz2 zend_extension=xdebug
And the necessary extensions will be loaded depending on the OS.
This mechanism will work when installing the extension and zend_extension in the ini-file, as well as an argument to the dl()
function.
But the absolute paths will still need to be specified with the -z
flag in CLI mode, as well as with the absolute path. The following example will not work:
extension=/path/to/extensions/bz2
Now you can reload abstract functions in the same way as regular functions:
abstract class A { abstract function bar(stdClass $x); } abstract class B extends A { abstract function bar($x): stdClass; } class C extends B { function bar($x): stdClass{} }
Before PHP 7.2, an error of the form was issued:
Fatal error: Can't inherit abstract function A::bar() (previously declared abstract in B)
The call number_format(-0.00)
returned string(1) “0”
, however number_format(-0.01)
returned string(2) “-0”
. Now, 0 without a sign will be returned.
Background:
In PHP, there are two types of data that contain a key / value. The first is arrays, which can contain keys in the form of strings or numbers. Moreover, if the string satisfies the rule /^(0|(-?[1-9][0-9]*))$/
and it is rather small PHP_INT_MIN ≤ n ≤ PHP_INT_MAX
, then it is converted into a numeric key.
The second type is objects in which numeric keys are not allowed, and keys are converted to strings.
In the Zend Engine, they are represented as a single HashTable
structure.
Now it is fixed.
Let's look at a couple of examples:
$obj = new stdClass; $obj->{'0'} = 1; $obj->{'1'} = 2; $obj->{'2'} = 3; $arr = (array) $obj; var_dump($arr); // , / var_dump($arr[1]); // . PHP 7.2 .
$arr = [0 => 1, 1 => 2, 2 => 3]; $obj = (object)$arr; var_dump($obj); // , / var_dump($obj->{'0'}); // . PHP 7.2 .
When null is passed as the get_class()
parameter inside the class context, the behavior of the function can be quite unexpected:
class Foo { function bar($repository) { $result = $repository->find(100); return get_class($result); } }
If $result
contains a valid object returned from the repository, the result of the function is the class name of this object.
If $result
is null
, the output will be the class context from which get_class()
is called, in this case Foo
.
This feature violates the principle of least surprise: “if the necessary function has a high coefficient of surprise, this function may need to be redesigned”.
Now a warning will be issued:Warning: get_class() expects parameter 1 to be object, null given in %s on line %d
If you want to keep the old behavior, you have to rewrite the code:
// : $x = get_class($some_value_that_may_be_null); // : if ($some_value_that_may_be_null === null) { $x = get_class(); } else { $x = get_class($some_value_that_may_be_null); }
Now, a call to count()
with a parameter that is scalar, null, or an object that does not implement the Countable interface will issue a Warning
.
One of the most hotly discussed changes is the possibility not to specify the type of the parameter in the heir. Thus, the heir will be able to accept a parameter of any type.
class ArrayClass { public function foo(array $foo) { /* ... */ } } class EverythingClass extends ArrayClass { public function foo($foo) { /* ... */ } }
Before PHP 7.2, an error was returned:
Warning: Declaration of EverythingClass::foo($foo) should be compatible with ArrayClass::foo(array $foo) in %s on line 18
In the pull request, opinions were divided.
Some said:
"Of course, let's send SOLID to hell. Who is Barbara Liskov ??? Some crazy woman? Of course! Let's allow breaking principles and ideas."
Others believe that:
"Restrictions like the principle of single responsibility should be implemented not at the level of the language, but in the application code. And now the letter L in SOLID will be at the discretion of the developer."
// $array = [1, 2, 3,]; // use Foo\Bar\{ Foo, Bar, Baz, };
It was planned to add such an opportunity for other lists, but at the voting stage they were canceled and will still return a Parse error
:
// fooCall($arg1, $arg2, $arg3,); // class Foo implements FooInterface, BarInterface, BazInterface, { // use FooTrait, BarTrait, BazTrait, ; // const A = 1010, B = 1021, C = 1032, D = 1043, ; protected $a = 'foo', $b = 'bar', $c = 'baz', ; private $blah, ; // function something(FooBarBazInterface $in, FooBarBazInterface $out,) : bool { } } // $foo = function ($bar) use ( $a, $b, $c, ) { // . . . };
Now, information from getaddrinfo()
implemented in C will be available from PHP. It is implemented in C. This is the missing function for the current socket library. When working with different networks, it would be useful to allow libc
tell us which connection / listening methods would be most appropriate given the set of hints.
Four functions were approved:
socket_addrinfo_lookup(string node[, mixed service, array hints]) : array socket_addrinfo_connect(resource $addrinfo) : resource socket_addrinfo_bind(resource $addrinfo) : resource socket_addrinfo_explain(resource $addrinfo) : array
Now:
tls://
has default value TLSv1.0 + TLSv1.1 + TLSv1.2
ssl://
is an alias to tls://
STREAM_CRYPTO_METHOD_TLS_*
has the default value TLSv1.0 + TLSv1.1 + TLSv1.2
instead of TLSv1.0
STREAM_CRYPTO_METHOD_SSLv23_CLIENT
constant is deprecated and will be removed later.Added new hint type: object
function acceptsObject(object $obj) { // ... } acceptsObject(json_decode('{}')); acceptsObject(new \MyObject()); acceptsObject(" "); function correctFunction() : object { $obj = json_decode('{}'); return $obj; } // function errorFunction() : object { return []; }
Added functions for using advanced LDAP operations in php-ldap.
// EXOP whoami $identity if (ldap_exop($link, LDAP_EXOP_WHO_AM_I, NULL, $identity)) { echo "Connected as $identity\n"; } else { echo "Operation failed\n"; } // , : $r = ldap_exop($link, LDAP_EXOP_WHO_AM_I); if (($r !== FALSE) && ldap_parse_exop($link, $r, $retdata)) { echo "Connected as $retdata\n"; } else { echo "Operation failed\n"; } // : if (ldap_exop_whoami($link, $identity)) { echo "Connected as $identity\n"; } else { echo "Operation failed\n"; } // : if (ldap_exop_passwd($link, 'uid=johndoe,dc=example,dc=com', '', 'newpassword')) { echo "Password changed\n"; } else { echo "Operation failed\n"; }
Libsodium is a modern cryptographic library that offers authenticated encryption, high-speed cryptography with elliptic curves, and much more. Unlike other cryptographic standards (which are a set of cryptographic primitives, for example, WebCrypto), libsodium includes carefully selected algorithms implemented by security experts. This will help avoid vulnerabilities in third-party channels.
Argon2 is a modern simple algorithm aimed at high speed of memory filling and efficient use of several computational blocks.
Since PHP5, the preferred structure for storing internal data has been objects. For some reason, the Hash extension used resources for this. This RFC is trying to correct a misunderstanding by transferring the Hash extension to store internal data in the form of objects.
Examples of using the resource as an internal representation:
resource hash_copy ( resource $context ) resource hash_init ( string $algo [, int $options = 0 [, string $key = NULL ]] )
The internal representation is converted from a resource to an object. Existing code should continue to work, if it does not use explicit is_resource () checks, these checks can be easily replaced with is_resource | is_object.
$db = new PDO(...); $stmt = $db->query('SELECT 1'); var_dump($stmt->activeQueryString()); // => string(8) "SELECT 1" $stmt = $db->prepare('SELECT :string'); $stmt->bindValue(':string', 'foo'); // var_dump($stmt->activeQueryString()); // => string(14) "SELECT :string" // $stmt->execute(); var_dump($stmt->activeQueryString()); // => string(11) "SELECT 'foo'"
$calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < ? AND colour = ?'); $sth->bindParam(1, $calories, PDO::PARAM_INT); $sth->bindValue(2, $colour, PDO::PARAM_STR); $sth->execute(); $sth->debugDumpParams(); /* : SQL: [82] SELECT name, colour, calories FROM fruit WHERE calories < ? AND colour = ? Sent SQL: [88] SELECT name, colour, calories FROM fruit WHERE calories < 150 AND colour = 'red' Params: 2 Key: Position #0: paramno=0 name=[0] "" is_param=1 param_type=1 Key: Position #1: paramno=1 name=[0] "" is_param=1 param_type=2 */
$db->quote('ĂĽber', PDO::PARAM_STR | PDO::PARAM_STR_NATL); // N'ĂĽber' $db->quote('A'); // 'A' $db->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_NATL); $db->quote('ĂĽber'); // N'ĂĽber' $db->quote('A', PDO::PARAM_STR | PDO::PARAM_STR_CHAR); // 'A'
For the json_encode
/ json_decode
, new JSON_INVALID_UTF8_IGNORE
and JSON_INVALID_UTF8_SUBSTITUTE
options have JSON_INVALID_UTF8_IGNORE
JSON_INVALID_UTF8_SUBSTITUTE
to ignore or replace invalid UTF-8 byte sequences.
The following functionality has been deprecated and has been removed.
E_WARNING
are now called E_WARNING
. In PHP2, such lines caused a Syntax error
, but in PHP3, the beta behavior was changed.
For example:
$foo = flase; // , E_NOTICE, . // ... if ( $foo ) { var_dump($foo); // string(5) "flase" }
The mcrypt extension, deprecated in PHP 7.1, has been moved to PECL.
The following functionality is deprecated and is no longer recommended for use.
This functionality will be removed in version 8.0.
The __autoload
function __autoload
been replaced by spl_autoload_register
back in version 5.1.
The main advantage of spl_autoload_register
is the ability to use multiple autoloaders. Deprecation notice
will now be thrown Deprecation notice
at compile time.
Png2wbmp()
and jpeg2wbmp()
are the only functions that change the format of images that can be called directly, available in ext / gd
, which makes them rather isolated, since libgd does not offer such functions. In addition, WBMP
was invented to support WAP
, which is now obsolete. Deprecation notice
will now be thrown.
The variable $php_errormsg
is created in the local scope when a non-fatal error occurs, if the track_errors
parameter track_errors
on (disabled by default) and the error is not intercepted by any error handler.
Besides the fact that the behavior depended on the ini-file settings, it was also magical. The error_get_last
function provides a cleaner way to get the latest error. With PHP 7, the error_clear_last
function is error_clear_last
, so all possible uses of $php_errormsg
without scoping.
create_function()
is a thin shell around the eval()
language construct that allows you to create a function with the generated name, argument list, and body as string arguments. Before the introduction of closures in PHP 5.3, it provided a way to create something similar to the lambda function.
Due to the nature of the work, create_function()
, in addition to a potential source of security problems, has very poor performance and memory usage characteristics. The use of real closures in all respects is preferable.
The mbstring.func_overload
parameter in the ini-file allows replacing a certain subset of string functions with analogues with the mbstring extension. For example, strlen()
will no longer return the length of the string in bytes, instead it returns the length in characters according to the currently selected internal encoding.
This means that code using mbstring.func_overload
not compatible with code written under the assumption that basic string operations work fine. Some libraries directly prohibit func_overload
(for example, symfony), other libraries stop working. Code that wants to support func_overload should conditionally switch between ordinary string functions and mbstring functions with 8-bit encoding (usually only libraries for cryptography try to do this).Deprecation notice
will now be thrown if mbstring.func_overload
contains a non-zero value.
Cast (unset)
turns the value into null. This means that (unset) expr
is just an expression that always returns null and has no other side effects.
In addition to being useless, this behavior is only confusing, since many people reasonably assume that (unset) $a
will behave like unset($a)
, but in reality this does not happen.Deprecation notice
will now be thrown Deprecation notice
at compile time.
The parse_str()
function parses the URL string and assigns values ​​to variables in the current context (or puts it into an array if the result parameter is specified).
It was highly recommended not to use this function without the result parameter, because the dynamic creation of variables in the scope of a function leads to exactly the same problems as register_globals. Deprecation notice
now thrown if the result parameter is not passed.
The gmp_random()
function generates a random number. The number will be in the range of zero before the product of the number limiter and the number of bits in the limb. If the limiter number is negative, a negative result will be returned.
Limb is an internal GMP mechanism. Technically, this is a part of a number that fits into one machine word. The number of bits in it may vary in different systems. Basically it is either 16 or 32, but this is not guaranteed. This happens because the GMP / MPIR implementation is not available to the user. Thus, the use of this function requires guessing the size of the Limb and may depend on the platform.
To fix this, in PHP 5.6, the gmp_random_bits()
and gmp_random_range()
functions were added, which allow you to precisely control the range of random numbers used. These functions should always be preferable to gmp_random()
.
Now, when calling gmp_random()
Deprecation notice
thrown.
The each()
function can be used to iterate over an array, like foreach
. In each call, it returns an array with the current key and value, and advances the pointer to the internal array to the next position. A typical use presented in the manual is as follows:
reset($array); while (list($key, $val) = each($array)) { echo "$key => $val\n"; }
The each
function is inferior to foreach
almost everything, among other things, it is 10 times slower.
Support for this feature poses a problem for some language changes. For example, in a warning for an invalid array container ( RFC ), list()
) had to be excluded, because the typical use of each
relies on the fact that you can access array shifts to false
without warning.
Now, Deprecation warning
thrown when you first call each
, because it is most often used in a loop.
The assert()
function has two modes of operation: if something other than a string is passed, it will check that the value is true. If a string was passed, it will be run via eval()
, and assert will check the validity of the result of eval()
.
The reason for this behavior is that prior to PHP 7, this was the only way to prevent expression evaluation. Starting with PHP 7, the zend.assertions
option in the ini file can be used to avoid evaluating expressions. Thus, it is no longer necessary to support the implicit evaluation of string arguments.
Using assert($value)
to validate the value opens a remote code execution vulnerability if there is a possibility that $value
will be a string.Deprecation notice
now thrown if assert()
used with a string argument.
Error handlers defined with set_error_handler()
are passed as the last argument to $errcontext
. This argument is an array containing all local variables in the location where the error was generated.
This feature is difficult to optimize because $errcontext
can be used to change all references and objects in the current scope. This functionality is almost never used. If you want to check the status variables at the location of the error, you must use a debugger.
Note that the error context contains only local variables. Backtrace errors, including $this
and function arguments, will remain available through debug_backtrace()
.
In this case, it is impossible to throw out the Deprecation warning
, so this functionality will simply be marked outdated in the documentation.
In PHP 7.2, the constant INTL_IDNA_VARIANT_2003 is deprecated.
In PHP 7.4, idn_to_ascii()
and idn_to_utf8()
will be changed, in which the default $variant
parameter will be INTL_IDNA_VARIANT_UTS46.
In PHP 8.0, support for INTL_IDNA_VARIANT_2003 will be removed.
Type (binary)
and support for the b
prefix were added in PHP 5.2.1
for compatibility with PHP 6
, but this version never appeared, and it is unknown whether there will ever be any attempt to implement binary strings. However, they are still accepted by the language scanner, although they are ignored.Deprecation notice
now thrown when using these castes.
Especially for version 7.2, I prepared a repository - " What's new in PHP ", which describes changes in PHP versions starting from 5.
The list in English can be found in the sources:
https://github.com/php/php-src/blob/PHP-7.2/UPGRADING
https://wiki.php.net/rfc#php_next_72
Try new version online:
https://3v4l.org/
As we see, global change is not enough.
And how do you feel about the changes in PHP? What feature did you like the most?
Source: https://habr.com/ru/post/335584/
All Articles