PHP 5.4 - What's new?

PHP 5.4 will be stable soon. In this post I'll try to give you an overview and examples of the new PHP 5.4 features.

If you want to try out PHP 5.4 (which is currently in RC6), it has to be installed first. I suggest that you try this out on a virtual machine so you don't break your current PHP version.

Installing PHP 5.4 on Ubuntu

#Fetch the signing key: curl | sudo apt-key add - # Then update your source list: # Debian Squeeze deb squeeze php54 # Ubuntu Natty deb natty php54 # update and install apt-get update apt-get install php5 php5-cgi libapache2-mod-php5

Improved Session extension

storing upload progress feedback in session data In the past it was possible to get the progress of an uploaded file through external packages like for instance uploadprogress but from now on it's possible to get the progress of uploaded files through session data.

Configuration of this feature is done in php.ini with the following parameters:

; Enable upload progress tracking in $_SESSION ; Default Value: On ; Development Value: On ; Production Value: On ; session.upload_progress.enabled = On ; Cleanup the progress information as soon as all POST data has been read ; (i.e. upload completed). ; Default Value: On ; Development Value: On ; Production Value: On ; session.upload_progress.cleanup = On ; A prefix used for the upload progress key in $_SESSION ; Default Value: "upload_progress_" ; Development Value: "upload_progress_" ; Production Value: "upload_progress_" ; session.upload_progress.prefix = "upload_progress_" ; The index name (concatenated with the prefix) in $_SESSION ; containing the upload progress information ; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" ; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" ; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" ; = "PHP_SESSION_UPLOAD_PROGRESS" ; How frequently the upload progress should be updated. ; Given either in percentages (per-file), or in bytes ; Default Value: "1%" ; Development Value: "1%" ; Production Value: "1%" ; session.upload_progress.freq = "1%" ; The minimum delay between updates, in seconds ; Default Value: 1 ; Development Value: 1 ; Production Value: 1 ; session.upload_progress.min_freq = "1"

As example, I created a page with 2 frames. One for uploading the files and one wich shows the session data. In the real world, you probably will track the progress with the help of some Ajax. If you try this example local, you better test it with a very big file. Otherwise uploading will be done before the respone is received. (Otherwise you have to set session.upload_progress.cleanup to Off to keep the session)


<? session_start();> ?> <HTML> <HEAD> <TITLE>Voorbeeld frames</TITLE> </HEAD> <FRAMESET ROWS="30%,70%"> <FRAME SRC="form.php"> <FRAME SRC="response.php"> </FRAMESET> </HTML>


<? session_start(); ?> <html> <head> </head> <body> <form action="" method="POST" enctype="multipart/form-data"> <input type="hidden" name="<?php echo ini_get(""); ?>" value="123" /> <input type="file" name="file1" /> <input type="file" name="file3" /> <input type="file" name="file2" /> <input type="file" name="file4" /> <input type="submit" /> </form> </body> </html>


<?php session_start(); ?> <html> <head> <meta http-equiv="refresh" content="1"> </head> <body> <? if (isset($_SESSION["upload_progress_123"])) { print_r($_SESSION["upload_progress_123"]); } ?> </body> </html>

Example output could be something like this where 3 files are uploaded and the 4th is being processed:

Array ( [start_time] => 1324664225 [content_length] => 444446321 [bytes_processed] => 398904160 [done] => [files] => Array ( [0] => Array ( [field_name] => file1 [name] => xxx.txt [tmp_name] => /tmp/phpVJK396 [error] => 0 [done] => 1 [start_time] => 1324664225 [bytes_processed] => 111111387 ) [1] => Array ( [field_name] => file3 [name] => xxx.txt [tmp_name] => /tmp/phpbkWd62 [error] => 0 [done] => 1 [start_time] => 1324664227 [bytes_processed] => 111111387 ) [2] => Array ( [field_name] => file2 [name] => xxx.sql [tmp_name] => /tmp/phpYVWD55 [error] => 0 [done] => 1 [start_time] => 1324664229 [bytes_processed] => 111111387 ) [3] => Array ( [field_name] => file4 [name] => xxx.sql [tmp_name] => [error] => 0 [done] => [start_time] => 1324664232 [bytes_processed] => 65569271 ) ) )

Expose session status Till now, it was not possible to know if a session was started or not. From now on, there is a new function to fetch the current sessionstatus. Documentation on the php site Request on the bugtracker

When you try this example, make sure session.auto_start in your php.ini file is 0. Otherwise session_status will always be 2 (Active)

<?php echo session_status(); session_start(); echo session_status(); //outputs 12 ?>

object-oriented session handlers Documentation on the php site RFC

I can't say much about this one because I couldn't get it working on my machine...

Built-in webserver

Documentation on the php site RFC

PHP 5.4 will be shipped with a built-in webserver. While it's not ready for use in production, it could be used for development and testing purpose. Using the built-in webserver is pretty simple. Just type in following code and the server starts listening for incoming requests on port 8080

php -S localhost:8080

It’s also possible to specify the document root and a PHP router-file from the command line

php -S localhost:8000 -t /My/website/directory router.php

The server analyzes the output of router.php When the script returns false, the requested resource (or 404) is returned as-is. When the script returns something else, that output is returned to the browser.

General improvements

Traits Documentation on the php site RFC Perhaps one of the biggest changes in PHP 5.4 is the added support for Traits A Trait, or in other language also known as a Mixin is a class that provides a certain functionality to be inherited or just reused by a subclass, while not meant for instantiation. Traits are particularly useful as a way to add common functionality to groups of classes that are otherwise not related in a type hierarchy. Error or Security logging is a common application where you can simply create logging versions of non logging classes by defining the logging version to inherit from the original class and the logging trait. Once that is done you can use the new class exactly like the old one and get logging without having to write any new code.

The downside is that the heavy use of traits can be confusing to debug, introduce unexpected side effects, introduce unexpected dependency loops and spread bugs across lots of classes - making them hard to pin down...

class Base { public function sayHello() { echo 'Hello '; } } trait SayWorld { public function sayHello() { parent::sayHello(); echo 'World!'; } } class MyHelloWorld extends Base { use SayWorld; } $hello = new MyHelloWorld(); $hello->sayHello();

Added support for array dereferencing RFC Probably the most common manifestation of this feature will be indexing arrays returned by functions, without actually assigning them to a variable.

function fruit () { return array('a' => 'apple', 'b' => 'banana'); } echo fruit()['a']; /* Outputs: apple */

Short array syntax RFC Yet another alias for creating arrays is added to PHP 5.4 From now on, you can just write the array between brackets.

$a = array(1,2,3); //old way $b = [1, 2, 3]; $c = array('foo'=>'orange','bar'=>'apple','baz'=>'lemon'); //old way $d = ['foo' => 'orange', 'bar' => 'apple', 'baz' => 'lemon']; $e = [1, 2, 3, ["foo" => "orange", "bar" => "apple", "baz" => "lemon"]]; print_r($b); print_r($d); print_r($e); /** Outputs: Array ( [0] => 1 [1] => 2 [2] => 3 ) Array ( [foo] => orange [bar] => apple [baz] => lemon ) Array ( [0] => 1 [1] => 2 [2] => 3 [3] => Array ( [foo] => orange [bar] => apple [baz] => lemon ) ) */

indirect method call through array Request on the bugtracker From now on, it's possible to call a function from an array where the first parameter is the classname and the second parameter is the functionname. I personally hate those constructs because they are very hard to debug when something goes wrong.

class Car { function assemble(){ echo 'car will be assembled'; } } $func = array('Car', 'assemble'); $func(); /* Outputs: car will be assembled */

Binary Notation for Integers RFC Request on the bugtracker From now on, PHP has a binary notation for integers just as it already does for decimal, octal, and hexadecimal representations

$bin = 0b0101010; print_r($bin); /* Outputs: 42 */

support for object references in recursive serialize() calls Request on the bugtracker Prior to PHP 5.4, object references where not saved in recursive serialize calls.

class A implements Serializable { public function serialize () { $serialized = array(); foreach($this as $prop => $val) { $serialized[$prop] = $val; } return serialize($serialized); } function unserialize($serialized) { foreach(unserialize($serialized) as $prop => $val) { $this->$prop = $val; } return true; } } class B extends A { public $A; } class C extends A { public $A; public $B; } $oC = new C(); $oC->A = new A(); $oC->B = new B(); $oC->B->A = $oC->A; echo $oC->A === $oC->B->A ? "yes" : "no", "\n"; $ser = serialize($oC); $new_oC = unserialize($ser); echo $new_oC->A === $new_oC->B->A ? "yes" : "no", "\n"; /** Outputs yes yes */

http_response_code function Documentation on the php site Request on the bugtracker With this new function it's possible to Get or Set the HTTP response code.

// Get the current default response code echo(http_response_code()); /** Outputs 200 */ // Set our response code http_response_code(404); // Get our new response code echo(http_response_code()); /** Outputs 404 */

header_register_callback() Documentation on the php site This callback registers a function that will be called when PHP starts sending output.

The callback is executed just after PHP prepares all headers to be sent, and before any other output is sent, creating a window to manipulate the outgoing headers before being sent.

header('Content-type: image/png'); function setPlainHeader() { foreach (headers_list() as $header) { header_remove($header); } header('Content-type: text/plain'); } echo "PHP rules!!"; $result = header_register_callback('setPlainHeader'); /** Outputs: PHP rules!! in the browser as plain text */

Improved Core functions

Instantiate a class without running constructor Documentation on the php site Request on the bugtracker When unserializing a class, it's not always desired to run the constructor. A new function is added to to ReflectionClass to instantiate a class without running the constructor. this feature can come in handy but I think this function can (and will) be abused a lot.

class wheels { public function __construct() { echo 'This is the first functioncall. '; } public function addWheels(){ echo 'This is the second function call....or not?'; } } $w = new wheels(); $w->addWheels(); // prints This is the first functioncall This is the second function call....or not? $w = new ReflectionClass("wheels"); $func = $w->newInstanceWithoutConstructor(); $func->addwheels(); //prints This is the second function call....or not?

number_format() function Documentation on the php site Request on the bugtracker number_format() no longer truncates multibyte decimal points and thousand separators to the first byte.

echo number_format(123456, 2, '.', 'test'); //output in PHP 5.4 : 123test456.00 //output in PHP 5.3 : 123t456.00

hex2bin() function Documentation on the php site hex2bin is a new function introduced in PHP 5.4. It translate hexadecimal characters into binair data. This function does exactly the opposite of the bin2hex() function

$hex = hex2bin("5048502072756c657321"); print_r($hex); /** Outputs: PHP rules! */

Added class member access on instantiation support A new feature is added to instantiate a class and call a function within this class in one operation. I don't really like the syntax but i love this feature

class Car{ function wheels(){ echo 'A car has wheels'; } } //PHP 5.3 $car = new Car(); $car->wheels(); //PHP 5.4 (new Car)->wheels();

Added class_uses function Documentation on the php site Request on the bugtracker This new function returns the traits used by the given class.

trait foo {} trait log {} trait foobar {} class bar { use foo; use foobar; } print_r(class_uses(new bar)); print_r(class_uses('bar')); /** * Result: * Array ( [foo] => foo [foobar] => foobar ) Array ( [foo] => foo [foobar] => foobar ) */

Added callable typehint. RFC This typehint allows a string with a function name, a closure, and an array composed of classname (or object) with method name. In PHP 5.3 this was only possible to do with the function call_user_func

class Car {   public function wheels($x) {      echo "The car has $x wheels";    }} call_user_func(array("Car","wheels"),'4');   //PHP 5.3 $f = array('Car','wheels');                 //PHP 5.4$f('4'); 

Array to String conversion notice When converting an array to a String will generate a notice (to see the notice on screen, you have to set the parameter display_errors ton On in your php.ini)

$arr = array(1,2); echo $arr; //Array to string conversion in /www/php54/general/arraytostringnotice.php on line 3

Class::{expr}() Makes PHP more flexible, when calling class/object functions. It's already possible to call a function in a class through a variable or a string. This, however didn't always work with a static call. From now on, static support is added.

class Test{ public function method() { echo 'Hello'; } public static function staticmethod() { echo 'Static'; } } $method = 'staticmethod'; $test = new Test(); $test->method(); //Prints Hello $test->$method(); //Prints Static $test->{'method'}(); //Prints Hello Test::method(); //Prints Hello Test::$method(); //Prints Static Test::{'method'}(); //Prints Hello -> This doesn't work in php < 5.4

Keep SoapClient alive Documentation on the php site Request on the bugtracker A new option is added to the SoapClient class to keep the connection alive

$client = new SoapClient("some.wsdl",array('keep_alive'=>1);

Improved JSON extension

JsonSerializable interface Documentation on the php site With this interface, you can specify data that should be serialized to JSON. In order to use this, you have to implement the function jsonSerialize()

class Car implements JsonSerializable { public $wheels; function jsonSerialize() { return json_encode($this); } } $car = new car(); $car->wheels = 4; echo $car->jsonSerialize();

Added option JSON_PRETTY_PRINT Request on the bugtracker With the option JSON_PRETTY_PRINT, the output of a JSON string will be displayed in a more human readable format

$obj = new stdClass; $obj->field1 = "hello"; $obj->field2 = "world"; $obj->field3 = array("key" => "value", "level2" => array(1,2,3)); echo json_encode($obj); echo json_encode($obj, JSON_PRETTY_PRINT); /*output: {"field1":"hello","field2":"world","field3":{"key":"value","level2":[1,2,3]}} { "field1": "hello", "field2": "world", "field3": { "key": "value", "level2": [ 1, 2, 3 ] } } */

Added option JSON_UNESCAPED_SLASHES Request on the bugtracker By default, JSON escapes slashes. With this new optionparameter, you can tell json_encode to not escape those slashes

$vars['url'] = ""; echo json_encode($vars) . PHP_EOL; echo json_encode($vars,JSON_UNESCAPED_SLASHES); /** output: {"url":"http:\/\/\/"} {"url":""} */

Improved CURL extension

Added support for CURLOPT_MAX_RECV_SPEED_LARGE and CURLOPT_MAX_SEND_SPEED_LARGE Documentation on the php site Request on the bugtracker

With this new options, it's possible to determine the maximum speed a connection can consume. It could come in handy for example when you don't want to stress your server

$time = microtime(true); // create a new cURL resource $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, ""); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); // grab URL and pass it to the browser $p = curl_exec($ch); // close cURL resource, and free up system resources curl_close($ch); echo microtime(true) - $time . PHP_EOL; $time = microtime(true); // create a new cURL resource $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, ""); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); curl_setopt($ch, CURLOPT_MAX_RECV_SPEED_LARGE,20000); $p = curl_exec($ch); curl_close($ch); echo microtime(true) - $time; /** Output: 0.61817121505737 5.2623569965363 */

Improved filesystem functions

SCANDIR_SORT_NONE Documentation on the php site Request on the bugtracker A new option in the scandir() function is added. Normally, all the files will be sorted ascending but with this function they won't be sorted. This could lead to a better performance handling very large directories.

$dir = '/home/wim/Downloads/php5.4-201112181630/build'; $files1 = scandir($dir); $files2 = scandir($dir,SCANDIR_SORT_NONE); print_r($files1); print_r($files2) /** output: Array ( [0] => . [1] => .. [2] => [3] => [4] => [5] => config-stubs [6] => [7] => libtool.m4 [8] => mkdep.awk [9] => order_by_dep.awk [10] => print_include.awk [11] => scan_makefile_in.awk [12] => shtool ) Array ( [0] => [1] => libtool.m4 [2] => . [3] => config-stubs [4] => [5] => [6] => order_by_dep.awk [7] => mkdep.awk [8] => [9] => shtool [10] => print_include.awk [11] => .. [12] => scan_makefile_in.awk )

Improved SPL extension

RegexIterator::getRegex() Documentation on the php site With this function, it's possible to get the regex-string used in the RegexIterator

$arrayiterator = new ArrayIterator(array('test1', 'test2', 'test3')); $regexiterator = new RegexIterator($arrayiterator, '/^(test)(\d+)/', RegexIterator::REPLACE); print_r($regexiterator->getRegex()); //outputs /^(test)(\d+)/

SplObjectStorage::getHash() Documentation on the php site This function calculates an identifier for the objects added to this SplObjectStorage object.

class car { public $wheels; } $storage = new SplObjectStorage(); $car = new car(); $car->wheels = 4; print_r($storage->getHash($car)); //outputs some random identifier //ex 0000000006c3c37d000000005f6560991

With this function you can for example prevent that duplicate objects are stored in your SplObjectStorageObject.

CallbackFilterIterator Documentation on the php site This is a cool little class where you can filter an iterator.

$array= array(1,2,3,4,5,6,7,8,9); $iterator = new ArrayIterator($array); function filter_even($current) { return $current %2 == 0 ? true: false; } $even_numbers = new CallbackFilterIterator($iterator, 'filter_even'); foreach($even_numbers as $even){ echo($even); //returns 2468 }


With this function, you can recursive filter an iterator.

$filterPhpFiles = function ($current) { if($current->isFile()) { if($current->getExtension()=== "php") return true; else return false; } return true; }; $iterator = new RecursiveDirectoryIterator('/home/wim/Downloads'); $files = new RecursiveCallbackFilterIterator($iterator, $filterPhpFiles); foreach (new RecursiveIteratorIterator($files) as $file) { if($file->isFile()){ echo $file->getFileName() . PHP_EOL; } }

Improved MySQL extension

Iterator support in MySQLi From now on, mysqli_result implements the Traversable interface so you can easily loop over the results

$mysqli = new mysqli('localhost', 'root', 'xxxx', 'cars'); $result = $mysqli->query("SELECT * FROM manufacturers LIMIT 10"); foreach($result as $manufacturer){ echo $manufacturer['name']; } $mysqli->close();
King Foo is a SensioLabs partner