The 5th Annual China PHP Conference

新機能

スカラー型宣言

スカラー 型宣言 には二つの方式があります。デフォルトの自動変換 (coercive) モードと、 厳密に判断する strict モードです。 パラメータとして、 文字列 (string)、整数 (int)、浮動小数点数 (float)、boolean (bool) といった型をいずれかの方式で強制できるようになりました。 これらは、PHP 5 で導入された型宣言 (クラス名やインターフェイス、配列そして callable) を強化するものです。

<?php
// デフォルトのモード
function sumOfInts(int ...$ints)
{
    return 
array_sum($ints);
}

var_dump(sumOfInts(2'3'4.1));

上の例の出力は以下となります。

int(9)

strict モードを有効にするには、ファイルの先頭に declare ディレクティブを置く必要があります。 つまり、スカラー型を厳密に扱うかどうかは、ファイル単位で定めるということです。 このディレクティブは、パラメータの型宣言だけでなく、関数の戻り値の型 (戻り値の型宣言を参照ください) や PHP の標準関数、そして拡張モジュールの関数にも影響を及ぼします。

スカラー型宣言に関するドキュメントやサンプルについては、 型宣言 を参照ください。

戻り値の型宣言

PHP 7 では、 戻り値の型宣言 もできるようになりました。 引数の型宣言 と同様に、戻り値の型宣言では、関数が戻す値がどの型になるかを宣言します。 戻り値の型宣言で使える は、引数の型宣言で使えるものと同じです。

<?php

function arraysSum(array ...$arrays): array
{
    return 
array_map(function(array $array): int {
        return 
array_sum($array);
    }, 
$arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

上の例の出力は以下となります。

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

詳細なドキュメントやサンプルについては、 戻り値の型宣言. を参照ください。

Null 合体演算子

null 合体演算子 (??) がシンタックスシュガーとして追加されました。 三項演算子と isset() を組み合わせる よくありがちなパターンを、より簡単に書くためのものです。 この演算子は、もし第一オペランドが非 NULL の値であればそれを返し、 そうでない場合は第二オペランドを返します。

<?php
// $_GET['user'] を取得します。もし存在しない場合は
// 'nobody' を用います。
$username $_GET['user'] ?? 'nobody';
// 上のコードは、次のコードと同じ意味です。
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// 合体演算子を連結することもできます。次のように書くと、
// $_GET['user']、$_POST['user'] そして 'nobody'
// の順に調べて、非 &null; が定義されている最初の値を返します。
$username $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

宇宙船演算子

宇宙船演算子は、二つの式を比較するために使うものです。 $a$b より大きい場合は 1、 $a$b が等しい場合は 0、 $a$b より小さい場合は -1 をそれぞれ返します。 比較の際には、 PHP 型の比較表 のルールを用います。

<?php
// 整数値
echo <=> 1// 0
echo <=> 2// -1
echo <=> 1// 1

// 浮動小数点数値
echo 1.5 <=> 1.5// 0
echo 1.5 <=> 2.5// -1
echo 2.5 <=> 1.5// 1
 
// 文字列
echo "a" <=> "a"// 0
echo "a" <=> "b"// -1
echo "b" <=> "a"// 1
?>

define() を用いた配列定数の定義

define() で配列の定数を定義できるようになりました。 PHP 5.6 までのバージョンでは、配列の定数は const でしか定義できませんでした。

<?php
define
('ANIMALS', [
    
'dog',
    
'cat',
    
'bird'
]);

echo 
ANIMALS[1]; // "cat" と出力します
?>

無名クラス

無名クラスをサポートするようになりました。new class を使って利用します。 その場限りの使い捨てのオブジェクトなどで、完全なクラス定義のかわりとして使えます。

<?php
interface Logger {
    public function 
log(string $msg);
}

class 
Application {
    private 
$logger;

    public function 
getLogger(): Logger {
         return 
$this->logger;
    }

    public function 
setLogger(Logger $logger) {
         
$this->logger $logger;
    }
}

$app = new Application;
$app->setLogger(new class implements Logger {
    public function 
log(string $msg) {
        echo 
$msg;
    }
});

var_dump($app->getLogger());
?>

上の例の出力は以下となります。

object(class@anonymous)#2 (0) {
}

詳細なドキュメントは 無名クラス を参照ください。

Unicode コードポイントエスケープ構文

Unicode のコードポイントを十六進形式で受け取って、 それを UTF-8 で (ダブルクォートで囲まれた文字列あるいはヒアドキュメントとして) 出力します。 妥当な形式のコードポイントならあらゆるものが使えます。先頭のゼロは省略してもかまいません。

echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";

上の例の出力は以下となります。

ª
ª (先頭のゼロを省略せずに書いても、前の行と同じ結果になります)
香

Closure::call()

Closure::call() は、オブジェクトのスコープをクロージャに一時的に束縛して実行するための、 より高性能で簡潔な方法です。

<?php
class {private $x 1;}

// 以前のバージョンのコード
$getXCB = function() {return $this->x;};
$getX $getXCB->bindTo(new A'A'); // 中間クロージャが必要
echo $getX();

// PHP 7 以降でのコード
$getX = function() {return $this->x;};
echo 
$getX->call(new A);

上の例の出力は以下となります。

1
1

unserialize() のフィルタリング

この仕組みは、信頼できないデータからオブジェクトを復元する際に、 よりセキュリティを高められるようにするために用意されたものです。 デシリアライズ可能なクラスの一覧をホワイトリストとして定義することで、 コードインジェクション攻撃を防ぎます。

<?php

// オブジェクトはすべて、__PHP_Incomplete_Class のオブジェクトに変換します
$data unserialize($foo, ["allowed_classes" => false]);

// MyClassとMyClass2以外のすべてのオブジェクトを、__PHP_Incomplete_Class のオブジェクトに変換します
$data unserialize($foo, ["allowed_classes" => ["MyClass""MyClass2"]]);

// デフォルト (第二引数を省略した場合) の挙動は以下のようになり、すべてのオブジェクトをそのまま復元します
$data unserialize($foo, ["allowed_classes" => true]);

IntlChar

ICU のさらなる機能を利用するために、新しく IntlChar クラスが追加されました。このクラスには数々の static メソッドと定数が定義されており、 これらを使って Unicode の文字を操作できます。

<?php

printf
('%x'IntlChar::CODEPOINT_MAX);
echo 
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

上の例の出力は以下となります。

10ffff
COMMERCIAL AT
bool(true)

このクラスを使うには、Intl 拡張モジュールをインストールしなければいけません。

Expectation

Expectations は、かつての assert() 関数を、下位互換性を保ったまま拡張したものです。 これを用いると、コストをかけずに実運用コードの中にアサーションを組み込めます。 そして、アサーションが失敗した際に自作の例外をスローできるようになります。

これまでの API も下位互換性を保つために維持されていますが、 assert() は言語構造となりました。 最初のパラメータには、単に評価対象の文字列や boolean 値を指定するだけではなく、式を渡せます。

<?php
ini_set
('assert.exception'1);

class 
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

上の例の出力は以下となります。

Fatal error: Uncaught CustomError: Some error message

開発環境および運用環境での設定方法などの詳細については、 assert() のマニュアルの expectation の節を参照ください。

use 宣言のグループ化

複数のクラスや関数そして定数を同じ namespace からインポートする際に、 単一の use 文にまとめられるようになりました。

<?php
// 以前のバージョンのコード
use some\namespace\ClassA;
use 
some\namespace\ClassB;
use 
some\namespace\ClassC as C;

use function 
some\namespace\fn_a;
use function 
some\namespace\fn_b;
use function 
some\namespace\fn_c;

use const 
some\namespace\ConstA;
use const 
some\namespace\ConstB;
use const 
some\namespace\ConstC;

// PHP 7 以降のコード
use some\namespace\{ClassAClassBClassC as C};
use function 
some\namespace\{fn_afn_bfn_c};
use const 
some\namespace\{ConstAConstBConstC};
?>

ジェネレータでの return

PHP 5.5 で導入されたジェネレータの機能拡張です。 ジェネレータの内部で return 文が使えるようになりました。 これを使えば、ジェネレータが最終的に返す式を指定できます (参照を返すことはできません)。 この値を取得するには、新しいメソッド Generator::getReturn() を用います。 このメソッドを使うのは、ジェネレータが値の生成を終えた後の一度だけになるでしょう。

<?php

$gen 
= (function() {
    
yield 1;
    
yield 2;

    return 
3;
})();

foreach (
$gen as $val) {
    echo 
$valPHP_EOL;
}

echo 
$gen->getReturn(), PHP_EOL;

上の例の出力は以下となります。

1
2
3

ジェネレータの最終値を明示的に返せる機能は、あれば便利なものです。 ジェネレータを実行したクライアント側のコードが、 ジェネレータが最後に返す値 (何らかのコルーチンの計算結果) を特別扱いできるようになるからです。 「取得した値が最後の値かどうかをまず調べて、最後であれば特別扱いする」 という処理をクライアント側で書くよりは、ずっとシンプルになります。

ジェネレータの委譲

ジェネレータを、別のジェネレータや Traversable オブジェクトそして配列に委譲できるようになりました。 外側のジェネレータに決まり文句を書いたりする必要はなく、単に yield from 構文を使うだけです。

<?php
function gen()
{
    
yield 1;
    
yield 2;
    
yield from gen2();
}

function 
gen2()
{
    
yield 3;
    
yield 4;
}

foreach (
gen() as $val)
{
    echo 
$valPHP_EOL;
}
?>

上の例の出力は以下となります。

1
2
3
4

intdiv() による整数の除算

新しい intdiv() 関数は、 オペランドに対して整数の除算を行い、その結果を返します。

<?php
var_dump
(intdiv(103));
?>

上の例の出力は以下となります。

int(3)

セッションのオプション

session_start() にオプションの配列を渡せるようになりました。 これは、php.ini などで設定した session 設定ディレクティブ を上書きします。

新たな設定オプション session.lazy_write をサポートするようになりました。これはデフォルトで有効になっており、 セッションのデータが書き換えられたときにだけセッションファイルを上書きします。 また、read_and_close も追加されました。 このオプションは session_start() だけに渡せるもので、 セッションデータを読み込んだら何も変更せずその場でクローズするよう指示します。

たとえば、 session.cache_limiterprivate にして、読み込んだセッションをすぐにクローズさせるには次のようにします。

<?php
session_start
([
    
'cache_limiter' => 'private',
    
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

新しい preg_replace_callback_array() 関数は、 preg_replace_callback() 関数を使ったコードをよりすっきりと書けるようにするものです。 これまでのバージョンの PHP では、正規表現ごとにコールバックを実行したければ、 コールバック関数が分岐だらけになってしまっていました。

PHP 7 以降では、個々の正規表現に対するコールバックを連想配列で登録できるようになりました。 連想配列のキーが正規表現で、その値がコールバックとなります。

CSPRNG 関数

暗号論的に安全な整数値および文字列を生成する、 プラットフォームに依存しない二つの新しい関数が追加されました。 random_bytes()random_int() です。

list() が常に、 ArrayAccess を実装したオブジェクトをアンパックできるように

これまでのバージョンでは、ArrayAccess を実装したオブジェクトに対して list() が正常に機能しないことがありました。 PHP 7 ではこの問題が修正されました。

その他の機能

  • クローンしたクラスのメンバーにアクセスできるようになりました。 (clone $foo)->bar() のようにできるということです。
add a note add a note

User Contributed Notes 3 notes

up
39
PawelD
10 months ago
<?php
class foo { static $bar = 'baz'; }
var_dump('foo'::$bar);
?>

if < php7.0

then we will receive a syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

but php7 returns string(3) "baz"

I think it's not documented anywhere
up
-4
omarv_r at yahoo dot com
9 months ago
lexx918, It is not working unexpectedly... lets see:

Calling to isset() method for a non existing property ($foo->bar in this case), automatically the magic method __isset() is invoked. So

$a = isset($foo->bar) ?: null; // __isset

is correct.

But when we try to evaluate $foo->bar, we are calling a getter. Because the bar property does not exist, the implicit calling is to magic method __get(). So

$a = $foo->bar ?? null; // __get

is correct too.
up
-19
lexx918 at mail dot ru
9 months ago
Sugar of ternary operator:
<?php
$a
?? 'b'
// allegedly equivalent to
isset($a) ? $a : 'b'
?>
.. in classes working unexpectedly:
<?php
class Foo {
    public function
__get($p) { echo "__get" . PHP_EOL; }
    public function
__isset($p) { echo "__isset" . PHP_EOL; }
}
$foo = new Foo;
$a = isset($foo->bar) ?: null; // __isset
$a = $foo->bar ?? null; // __get
?>
To Top