What’s New in PHP 5.3

In PHP 5.3, as in the entire fifth branch of PHP, a new script engine Zend Engine 2.0 is included. Thanks to this, PHP started to run faster by about 15-20%.

?: — shorthand for the ternary operator

With PHP 5.3 it became possible not to write the middle part of the ternary operator. The expression expr1 ?: expr3 returns expr1 if expr1 is not empty, and expr3 otherwise.

Ternary — consisting of three parts, components.

$a = $expr1 ?: $expr3;
// equivalent to:
$a = $expr1 ? $expr1 : $expr3;

Example of the ternary operator:

// full form
if ( $a > 100 )
	$result = "Greater";
else
	$result = "Lower";

// short form
$result = $a > 100 ? "Greater" : "Lower";

In the short form there is also a performance nuance, for example:

// full form
if ( get_post_meta(25, 'meta_key', 1) )
	echo esc_html( get_post_meta(25, 'meta_key', 1) );
else
	echo 'Meta field does not exist';

// short form
echo esc_html( get_post_meta(25, 'meta_key', 1) ?: 'Meta field does not exist' );

In the full form the function get_post_meta() is invoked 2 times. In the short form, once, and if it returns something, the value is immediately passed to the second argument of the ternary operator: no extra variables are needed...

$func = function() use (){ } — anonymous (lambda) functions

Lambda functions are also called “anonymous functions” because they do not have a name.

Lambda functions are closures — a special kind of function defined inside another function and created each time it is executed. Syntactically it looks like a function entirely contained within the body of another function. As far as I understand, any function is a closure of the current context, i.e., the context will not be cleared while the function is running. But if a lambda function is inside a function, it becomes a closure, and if variables from the outer function are passed to it, they will not be cleared until the inner function finishes running...

In earlier versions, anonymous functions were created using the create_function() function.

Example of creating an anonymous function for sorting with usort():

$arr = array(3, 2, 5, 6, 1);

usort( $arr, function($a, $b) {
	if ( $a == $b )
		return 0;

	return ( $a > $b ) ? -1 : 1;
});

Another feature of lambda functions is lexical binding (using variables from the current scope) via the use operator:

$var = 'Hello, Bear!';
$func = function() use ( $var ) { echo $var; };
$func(); //> Hello, Bear!

Variables are passed by value, but you can pass a reference to a variable by using &:

$var = 'Hello, Bear!';
$func = function() use ( & $var ) { $var = $var .' We’re visiting!'; };
$func(); // call
echo $var; //> Hello, Bear! We’re visiting!

method()->var — obtaining an object from a method/function

This is convenient:

$object->method()->method()->method();
$object->method()->method()->member = 5;

In PHP below 5.3 it was written like this:

$tmp = & $object->method();
$tmp = & $tmp->method();
$tmp->method();

<<<'DOC' — NOWDOC support

In PHP 5.3 you can use the analog of HEREDOC, which is called NOWDOC. The feature is that inside it variables remain plain text, as if you wrote them in a single-quoted string: 'text $foo':

$foo = 'Summer';

// HEREDOC was in 5.2
$str = <<<DOC
	Text with variable '$foo'
DOC;

echo $str; // Text with variable 'Summer'

// NOWDOC appeared in 5.3
$str = '<<<DOC'
	Text with variable '. $foo .'
DOC;

echo $str; // Text with variable '. $foo .'

namespace — namespace support

Namespaces are needed to avoid conflicts when function/class/variable/constant names coincide. In short: identical names in different namespaces are different names.

The example below should explain almost everything that is possible in namespaces. For details, head to the official documentation here.

<?php
#
# The namespace declaration must be at the very top of the file containing the namespace,
# i.e. before any code except the reserved declare(encoding='...');.
# Also nothing should be output to the screen before the namespace declaration
# The same namespace can be defined in different files. This way these files belong to the same namespace

# Declare the my\name namespace
namespace my\name;

// Getting the namespace name dynamically --------------
$s = __NAMESPACE__; //> my\name
$s = __NAMESPACE__ . '\HELLO'; //> my\name\HELLO
// namespace: there is also a special word namespace, which is used for dynamically
// obtaining the name of the current namespace when calling functions/methods/constants (see below)

// GLOBAL functions/classes/constants in our namespace --------------
$s = strlen('hi');           // will call my\name\strlen() - if the function exists in our namespace, else the global strlen()
define('HELLO', 'HI everyone');  // will add a constant to the global space "\HELLO"

# Access to global classes/functions/constants from within a namespace
$a = \strlen('hi'); // calls the global strlen()
$b = \ABSPATH;      // accesses the global ABSPATH constant
$c = new \WP_Query; // creates an instance of the global WP_Query class

// FUNCTION in our namespace --------------
function my_func(){ return 'My function'; }

// Call
my_func();           //> "My function"
namespace\my_func(); //> "My function"
\my\name\my_func();  //> "My function"
// my\name\my_func();   //> error: will call my\name\my\name\my_func()
// such syntax can be used to access sub-namespaces of our namespace

// FUNCTION in our namespace that exists in the global space --------------
function trim( $str ){
	return \trim( $str, '-' ); # if you call trim( $str, '-' ), the function will call itself...
}

// Call
$s = trim('-foo');           // call trim() from the current namespace. Output: foo
$s = \my\name\trim('-foo');  // same as above
$s = namespace\trim('-foo'); // same as above

$s = \trim('-foo'); // call trim() from the global space. Output: -foo

// CONSTANTS in our namespace --------------
const HELLO = 'HI';                     // add a constant to the current namespace
define('my\name\HELLO', 'HI');          // same as above
define(__NAMESPACE__ . '\HELLO', 'HI'); // same as above

// Call
$s = HELLO;           //> HI - if the constant exists in the current namespace, or the global constant value
$s = \my\name\HELLO;  //> HI
$s = namespace\HELLO; //> HI
$s = \HELLO;          //> HI everyone - global HELLO constant

// CLASS in our namespace --------------
class MyClass {
	function method(){ return 'method of MyClass'; }
	static function static_method(){ return 'static method of MyClass'; }
}

// Call
$a = new MyClass;            // reference to MyClass from the current namespace
$a = new \my\name\MyClass;   // same as above

$s = namespace\MyClass::static_method(); //> 'static method of MyClass' - calls static method "static_method" of class my\name\MyClass.
$s = $a::static_method();                // same as above

$s = $a->method();                       //> 'method of MyClass' - calls the "method" of class my\name\MyClass
										 // namespace\MyClass->method() - such a method call will throw an error - syntax error

// INJECTION of functions/methods/constants into our namespace from other namespaces --------------

// NOTE: use operators can be combined: separate with comma
// For example: use other\name\OtherClass as Another, other\name\NSname;

use other\name\OtherClass as Another;
$obj = new Another; // creates an object of class other\name\OtherClass

use other\name; // now name = other\name
name\other_func(); // calls function other\name\other_func();

// import global class
use WP_Query;
$a = new WP_Query(); // creates an instance of WP_Query class
					 // without the "use WP_Query;" statement, an instance of my\name\WP_Query would be created

// import function (PHP 5.6+)
use function other\name\other_func;
$s = other_func(); //> "Another Function" - result of other\name\other_func()

// import function under alias func (PHP 5.6+)
use function other\name\other_func as func;
$s = func();         //> "Another Function" - result of other\name\other_func()

//const other\name\HELLO2 = 'Hello again!'; // will raise a syntax error, which is odd
define('other\name\HELLO2', 'Hello again!');

// import constant (PHP 5.6+)
use const other\name\HELLO2;
$s = HELLO2; //> "Hello again!" - contents of other\name\HELLO2 constant

// ONE MORE NAMESPACE in one file --------------
// More details: http://php.net/manual/ru/language.namespaces.definitionmultiple.php

namespace other\name;

class OtherClass {}
function other_func() { return 'Another Function'; }

// When describing several namespaces in one file, it is better to use braces syntax:
/*
namespace MyProject {
	function connect() {}
}

namespace AnotherProject {
	function connect() {}
}
*/

__DIR__ — new magic constant

__DIR__ contains the directory of the current file — the file in which it is used. Returns the full path to the current file without a trailing slash, except for the root directory.

__DIR__ can be replaced with:

dirname(__FILE__)

$class::$foo — dynamic class reference

This provides dynamic access to static methods/properties of a class:

class C {
	static $foo = 'foo';
}

$class = 'C';
echo $class::$foo; //> foo

const — keyword for creating constants outside classes

A simple example where everything is clear:

define('SHORTINIT', 'true');

// now you can declare a constant like this:
const SHORTINIT = 'true';

Unlike define(), such constants must be declared in the top-level scope, because they are defined at compile time. This means you cannot declare them inside functions/loops/expressions if or try/catch blocks.

static::method() — late static binding

Static binding of a method/property ties it to the class from which it is called, not the class in which it is defined. See the example:

class A {
	static function who() {
		echo __CLASS__;
	}

	static function test1() {
		self::who();
	}

	static function test2() {
		static::who(); // late static binding
	}
}

class B extends A {
	static function who() {
		echo __CLASS__;
	}
}

echo B::test1(); //> A
echo B::test2(); //> B
echo B::who(); //> B

Read more about late static binding in the documentation: http://php.net/manual/ru/language.oop5.late-static-bindings.php.

goto hell; — goto operator

Used to jump to another part of the program. The target label is indicated by a label followed by a colon; after the goto operator, the desired label for the jump is specified.

The target label must be in the same file and the same context. That is, you cannot exit the function or method, so you cannot jump inside any function.

You also cannot jump into any loop or switch statement. But you can exit from any loop, so "goto" is convenient as a replacement for multi-level breaks.

Example of using goto:

function rabbit(){
	$i = 1;
	$out = '';
	start: $out .= ($i > 1 ? '-' : '' ) .$i;

	if( $i++ < 5 ){ goto start; }

	return $out . ' the rabbit went for a walk';
}

echo rabbit(); //> 1-2-3-4-5 rabbit went for a walk

Example of using goto inside a loop:

for( $i=0, $j=50; $i<100; $i++ ) {
	while( $j-- ) {
		if( $j==17 ) goto end;
	}
}
echo "i = $i"; // will be skipped

end: echo 'j reached 17';

__callStatic(), __invoke() — magic methods

__callStatic() — fires when a non-existent static method is called: Foo::bar():

class A {
	static function __callStatic( $name, $args ){
		return $name .' '. print_r( $args, 1 );
	}
}
echo A::no_matter_what('bar');
/* Output:
no_matter_what Array
(
	[0] => bar
)
*/

__invoke() — fires when an object is invoked as a function: $obj():

class A {
	function __invoke( $var ){
		var_dump( $var );
	}
}
$obj = new A;
$obj('foo'); //> string(3) "foo"