The most exciting features of PHP 7.1

by Enrico Zimuel
Senior Software Engineer
Rogue Wave Software, Inc.


ZendCon 2017, Las Vegas (NV), Oct. 26

About me

PHP 7.1

  • 7.1.0 released (01 Dec 2016)
  • Latest is 7.1.10 (29 Sep 2017)

By numbers

  • 376 bug fixes
  • 12 new features
  • 13 new functions
  • 36 new global constants
  • 20 backward incompatible changes
  • 2 deprecated features
  • 16 changed functions
  • 7 other changes

New Features

Nullable types

  • For parameters and return values
  • Prefixing the type name with a ?
  • NULL can be passed as an argument,
    or returned as a value

Example


function hi(?string $name): ?string
{
    if (null === $name) {
        return null;
    }
    return 'Hello ' . $name;
}

echo hi(null); // returns null
echo hi('Enrico'); // returns 'Hello Enrico'
echo hi(); // Fatal error

Example (2)


interface Fooable {
    function foo(): ?Fooable;
}
interface StrictFooable extends Fooable {
    function foo(): Fooable; // valid
}

interface Fooable {
    function foo(): Fooable;
}
interface LooseFooable extends Fooable {
    function foo(): ?Fooable; // invalid
}

Example (3)


interface Fooable {
    function foo(Fooable $f);
}
interface LooseFoo extends Fooable {
    function foo(?Fooable $f); // valid
}

interface Fooable {
    function foo(?Fooable $f);
}
interface StrictFoo extends Fooable {
    function foo(Fooable $f); // invalid
}

Void Return Type


function swap(&$left, &$right): void
{
    if ($left === $right) {
        return;
    }
    $tmp   = $left;
    $left  = $right;
    $right = $tmp;
}
$a = 1;
$b = 2;
var_dump(swap($a, $b), $a, $b); // null, 2, 1

Array destructuring


$data = [['foo', 'bar', 'baz']];
[$a, $b] = $data[0];
var_dump($a, $b); // string(3) "foo", string(3) "bar"
[$a, , $c] = $data[0];
var_dump($a, $c); // string(3) "foo", string(3) "baz"
foreach ($data as [$a, $b, $c]) {
    var_dump($a, $b, $c);
    // string(3) "foo"
    // string(3) "bar"
    // string(3) "baz"
}

Support for keys

Specify keys in list(), or its new shorthand [] syntax


$data = ['a' => 'foo', 'b' => 'bar', 'c' => 'baz'];

list('a' => $a, 'b' => $b, 'c' => $c) = $data;
var_dump($a, $b, $c); // foo, bar, baz

['a' => $a, 'b' => $b, 'c' => $c] = $data;
var_dump($a, $b, $c); // foo, bar, baz

No mix list() and [ ]


// Not allowed
list([$a, $b], [$c, $d]) = [[1, 2], [3, 4]];
[list($a, $b), list($c, $d)] = [[1, 2], [3, 4]];

// Allowed
list(list($a, $b), list($c, $d)) = [[1, 2], [3, 4]];
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];

Iterable

  • Added the iterable pseudo-type
  • It accepts array or Traversable
  • Can be used in parameter and return types

Example


function foo(iterable $iterable): void
{
    foreach ($iterable as $value) {
        var_dump($value);
    }
}

foo([1,2,3]);
foo(new ArrayIterator([1,2,3]));

Class CONST visibility


class ConstDemo
{
    const CONST_A = 1; // public
    public const CONST_B    = 2;
    protected const CONST_C = 3;
    private const CONST_D   = 4;
}

Using Reflection


$obj = new ReflectionClass("ConstDemo");
foreach ($obj->getReflectionConstants() as $const) {
    var_dump($const); // ReflectionClassConstant
    var_dump($const->getName());
    var_dump($const->getValue());
    var_dump($const->isPublic());
    var_dump($const->isPrivate());
    var_dump($const->isProtected());
}

More info: ReflectionClassConstant

Multiple catch {}


try {
   // Some code...
} catch (ExceptionA | ExceptionB $e) {
   // Handle exceptions A or B
} catch (\Exception $e) {
   // ...
}

Negative offsets


var_dump("abcdef"[-2]); // string(1) "e"
var_dump("abcdef"[-7]); // string(0) "", PHP Notice
// strpos
var_dump(strpos("aabbcc", "b", -3)); // int(3)

// get the last character of a string
$last = substr($foo, -1); // before PHP 7.1
$last = $foo[-1];

Async signal handling

pcntl_async_signals() has been introduced to enable asynchronous signal handling without using ticks


pcntl_async_signals(true); // turn on async signals
pcntl_signal(SIGHUP,  function($sig) {
    echo "SIGHUP\n";
});
posix_kill(posix_getpid(), SIGHUP);

Closure from callable


class Test
{
  public function exposeFunction() {
    return Closure::fromCallable([$this, 'privF']);
  }
  private function privF($param) {
    var_dump($param);
  }
}
$privFunc = (new Test)->exposeFunction();
var_dump($privFunc); // object(Closure)
$privFunc('some value'); // string(10) "some value"

OpenSSL AEAD

Authenticated Encrypt with Associated Data (AEAD)

Support GCM and CCM encryption modes

GCM is 3x faster than CCM. See this benchmark

More info on Authenticated Encryption in PHP 7.1

openssl_encrypt()


string openssl_encrypt(
    string $data,
    string $method,
    string $password,
    [ int $options = 0 ],
    [ string $iv = "" ],
    [ string &$tag = NULL ],
    [ string $aad = "" ],
    [ int $tag_length = 16 ]
)

$tag contains the authentication hash

openssl_decrypt()


string openssl_decrypt(
    string $data,
    string $method,
    string $password,
    [ int $options = 0 ],
    [ string $iv = "" ],
    [ string $tag = "" ],
    [ string $aad = "" ]
)

$tag is the authentication hash

Encrypt example


$algo = 'aes-256-gcm';
$iv   = random_bytes(openssl_cipher_iv_length($algo));
$key  = random_bytes(32); // 256 bit
$data = random_bytes(1024); // 1 Kb of random data
$ciphertext = openssl_encrypt(
    $data,
    $algo,
    $key,
    OPENSSL_RAW_DATA,
    $iv,
    $tag
);

Output is $ciphertext . $tag

Decrypt example


$decrypt = openssl_decrypt(
    $ciphertext,
    $algo,
    $key,
    OPENSSL_RAW_DATA,
    $iv,
    $tag
);
if (false === $decrypt) {
    throw new Exception(openssl_error_string());
}
echo $data === $decrypt ? 'Ok' : 'Failure';

HTTP/2 Server Push

  • Server push has been added to CURL 7.46+
  • Use curl_multi_setopt() function with the new CURLMOPT_PUSHFUNCTION constant
  • Added CURL_PUSH_OK and CURL_PUSH_DENY to approve or deny the callback execution

Example


$transfers = 1;
$callback = function($parent_ch, $pushed_ch, array $headers)
            use (&$transfers) {
    $transfers++;
    return CURL_PUSH_OK;
};
$mh = curl_multi_init();
curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $callback);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://localhost:8080/index.html");
curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // self-signed cert
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // self-signed cert
curl_multi_add_handle($mh, $ch);

Example (2)


$active = null;
do {
    $status = curl_multi_exec($mh, $active);
    do {
        $info = curl_multi_info_read($mh);
        if (false !== $info && $info['msg'] == CURLMSG_DONE) {
            $handle = $info['handle'];
            if ($handle !== null) {
                $transfers--; // decrement remaining requests
                $body = curl_multi_getcontent($info['handle']);
                curl_multi_remove_handle($mh, $handle);
                curl_close($handle);
            }
        }
    } while ($info);
} while ($transfers);
curl_multi_close($mh);

New hash functions

Added hash_hkdf() function to support HKDF (RFC 5869)


$key = random_bytes(32);
$salt = random_bytes(16);

$encryptKey = hash_hkdf('sha256', $key, 32, 'encrypt', $salt);
$authKey = hash_hkdf('sha256', $key, 32, 'auth', $salt);

var_dump($encryptKey !== $authKey); // bool(true)

Added SHA3 support (224, 256, 384, and 512)


$hash = hash('sha3-224', 'This is a text');
var_dump($hash);
// string(56)"9209f5869ad03ac11549902b3c83fe8e6b7e1cd1614ab4291587db43"

More to come with PHP 7.2

GA: Nov 30 2017

Thanks!

Rate this talk at https://joind.in/talk/f8f7e

Contact me: enrico [at] zend.com

Follow me: @ezimuel