King Foo

King Foo

You are in:

King Foo > Blog > PHP > PHP 5.4 – What’s new?

Blog

PHP 5.4 – What’s new?

Posted by
/ / 15 Comments

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 http://apt.damz.org/key.gpg | sudo apt-key add -
# Then update your source list:
# Debian Squeeze
deb http://apt.damz.org/debian squeeze php54

# Ubuntu Natty
deb http://apt.damz.org/ubuntu 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
; http://php.net/session.upload-progress.enabled
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
; http://php.net/session.upload-progress.cleanup
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_"
; http://php.net/session.upload-progress.prefix
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"
; http://php.net/session.upload-progress.name
session.upload_progress.name = "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%"
; http://php.net/session.upload-progress.freq
session.upload_progress.freq =  "1%"

; The minimum delay between updates, in seconds
; Default Value: 1
; Development Value: 1
; Production Value: 1
; http://php.net/session.upload-progress.min-freq
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)

index.php:


<? session_start();> ?>

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

form.php:


<? session_start(); ?>
<html>
    <head>

    </head>
    <body>

        <form action="" method="POST" enctype="multipart/form-data">
            <input type="hidden" name="<?php echo ini_get("session.upload_progress.name"); ?>" 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>

response.php:


<?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'] = "http://www.example.com/";
echo json_encode($vars) . PHP_EOL;
echo json_encode($vars,JSON_UNESCAPED_SLASHES);

/** output:
{"url":"http:\/\/www.example.com\/"}
{"url":"http://www.example.com/"}
 */

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, "http://slashdot.org/");
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, "http://slashdot.org/");
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] => build.mk
    [3] => build2.mk
    [4] => buildcheck.sh
    [5] => config-stubs
    [6] => genif.sh
    [7] => libtool.m4
    [8] => mkdep.awk
    [9] => order_by_dep.awk
    [10] => print_include.awk
    [11] => scan_makefile_in.awk
    [12] => shtool
)
Array
(
    [0] => genif.sh
    [1] => libtool.m4
    [2] => .
    [3] => config-stubs
    [4] => build.mk
    [5] => build2.mk
    [6] => order_by_dep.awk
    [7] => mkdep.awk
    [8] => buildcheck.sh
    [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
}

RecursiveCallbackFilterIterator

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();
  1. 25/08/2012

    dennis iversen

    looking forward to use the build in web server.. Then it will maybe be possible – over time – to distribute a complete system in one file :)

  2. 16/02/2012

    tmak

    Very nice article.
    The jsonSerialize example you’ve provided causes php to segfault.
    Noticed that in other places, they seem to use it differently, as in:


    class Foo implements JsonSerializable {
    function jsonSerialize() {
    return array ('foo' => 42 );
    }
    }

    $foo = new Foo ();
    echo json_encode ( $foo ); // {"foo":42}

  3. 30/01/2012

    Cr@zy

    Hum nice, I’ll keep an eye on it :)

  4. 28/01/2012

    Roland F

    Does anyone know when RC6 becomes available in ubuntu (11.10) synaptic or how to get it? Easily of course.

    It’s currently RC3… not cool.

    • 29/01/2012

      wimm

      As far as I know, RC6 isn’t available as an ubuntu package yet.
      You can try compile from source or just wait a few days/weeks before it comes available.
      I personally don’t bother RC6 is not available yet. The differences between RC3 and RC6 are really very small.

      • 14/07/2012

        Peter

        :)

  5. 24/01/2012

    Hirvine

    In your last example you echo $manufacturer … :S Isn’t $manufacturer not an array or object? Can you select the fetch mode?

    It’s still painful to see these new types of array. I wanted the ruby array so badly :P…

    Thanks for putting all the features in a single overview. Nice job.

    • 24/01/2012

      wimm

      You are absolutely right Hirvini.
      $manufacturer should be an array containing databasefields=>values.

      I didn’t read anything in the documentation about the fetch mode so I don’t think it’s possible to fetch them by default as objects

      Thanks for your comment.

  6. 24/01/2012

    Ossama Khayat

    Thanks for the great review.
    One very important addition is JSON_UNESCAPED_UNICODE
    This output unicode chars without encoding, which is great for non-latin chars.

  7. 24/01/2012

    Ricardo Maia

    I’m very disappointed because scalar types are removed from this release version.

    I’d like to have type hint for integers, strings, booleans etc.

    Maybe this features could be present in PHP 6. I hope!

    • 25/01/2012

      Grayson Koonce

      Agreed. I was really hoping for scalar type hints. Return type hints would have been amazing as well. Too bad. Maybe PHP 6.

Leave a comment

Please wrap all source codes with [code][/code] tags.
  1. PHP PHP 5.4 released! - 9lives - Games Forum03-01-12
  2. Mingguan PHP #1 | pakephp!02-04-12
  3. KingFoo Blog: PHP 5.4 – What’s new? | Scripting4You Blog01-24-12