そろそろPHP7.4がやってくるみたいです。
今回はどんな変化があったのでしょうか。
引数の型の反変性と戻り値の型の共変性のサポート
反変性および共変性という言葉を皆さんご存知でしたか?僕は…初めて聞きました。
PHP7.4では、クラスを継承してオーバーライドする際、以下のような記述が可能になります。
<?php
class A {}
class B extends A {}
class Producer {
public function method(B $b): A {}
}
class ChildProducer extends Producer {
public function method(A $a): B {}
}
クラス A とそれを継承したクラス B 、そして、クラス Producer とそれを継承したクラス ChildProducer と4つのクラスがあります。
ChildProducer は Producer の method メソッドをオーバーライドしています。
ここで method メソッドの引数と戻り値の型をよく見てみましょう。
Producer では引数の型が B になっているのに対し、ChildProducer では A となっています。
一方戻り値の型はというと、Producer では A となっているのに対し、ChildProducer では B となっています。
ちょうど引数と戻り値が正反対の関係になっています。
引数の型は Producer → ChildProducer という継承の流れに逆らって B → A と変化し、
戻り値の型は Producer → ChildProducer の流れに沿って、A → B と変化しています。
このクラスの変化を引数の型の反変性やら戻り値の型の共変性などというようです。
なぜそのような変化が可能なのか。それを説明するには僕の知識が足りないのでグーグルとかで調べましょう。
ちなみに引数の型の反変性自体はPHP7.4以前でも使用出来たみたいですが、Warningが出ていました。
戻り値の型の共変性はPHP7.4以前では Fatal error となります。
型付きプロパティ
クラスのプロパティに型を指定できるようになりました。
<?php
class User {
public int $id;
public string $name;
}
Null合体代入演算子
x = x ?? y をさらに省略して x ??= y と書けるようになりました。
ちなみに ?? はPHP7.0から追加されたNull合体演算子で、以下のシンタックスシュガーです。
$_GET['user'] = isset($_GET['user']) ? $_GET['user'] : 'nobody'; $_GET['user'] = $_GET['user'] ?? 'nobody'; // Null合体演算子 $_GET['user'] ??= 'nobody'; // Null合体代入演算子
アロー関数
無名関数を定義する際のシンタックスシュガーです。ただ、全く同じと言うわけではないので注意しましょう。
$factor = 10; $f = fn($n) => $n * $factor; $nums = array_map($f, [1, 2, 3, 4]);
use が不要になりました。関数内で使用している変数と同名の変数が外側にある場合、アロー関数定義時に値渡しされます。
また、関数の処理部分は1行しか書けません。複数行に渡る処理が必要な場合は今まで同様 function(...) use(...) {} で書く必要があります。
また、この構文の追加に伴い、グローバルスコープで fn という名前の関数を定義するとシンタックスエラーが出るようになりました。
function fn() {}
// Parse error: syntax error, unexpected 'fn' (T_FN), expecting '(' in /var/www/html/index.php on line 2
配列内でのスプレッド演算子
配列Aの中で配列Bにスプレッド演算子を使うことで、配列Aのなかに配列Bの要素を展開(アンパック)できるようになります。
$parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon']; // ['banana', 'orange', 'apple', 'pear', 'watermelon'];
これにより、添字配列では array_merge() 関数が実質不要となりました。
連想配列には使用できないため、その場合はこれまで通り array_merge() などを使いましょう。
また、ジェネレータ関数をスプレッド演算子で展開することも可能です。
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
yield $i;
}
}
$a = [...gen_one_to_three()];
// [1, 2, 3];
弱い参照
今まで拡張機能として存在していた弱い参照(Weak Reference)ですが、PHP7.4からはPHP本体が提供するようになるそうです。
$obj = new stdClass;
$weakref = WeakReference::create($obj);
var_dump($weakref->get()); // object(stdClass)#1 (0) { }
unset($obj);
var_dump($weakref->get()); // NULL
PHP本体が提供することで、他のPHP本体の関数との相性が良くなることが期待できます。
FFI
C言語で定義された関数や変数、データ構造をPHPから使用できるようにする拡張機能、とのことです。
$ffi = FFI::cdef("double sin(double x);","libm.so.6");
var_dump($ffi->sin(1)); // float(0.8414709848079)
この例では libm.so.6 で定義されている sin() 関数をPHPから使用しています。
これによって速度に差が出るかどうかは良くわかりませんでした。遅くなると言う声も?
これの大きなメリットは PHP に縛られずに部分部分で適した言語が使えるようになる、と言うことだと思われます。
この機能を使って PHP からTensorFlowの機能を使うプロジェクトもある模様。
https://github.com/dstogov/php-tensorflow
https://column.prime-strategy.co.jp/archives/column_3179
mb_str_split() が追加
str_split() のマルチバイト文字版です。なかったんですね。
使うかどうかは…どうなんだろう。
var_dump(mb_str_split("あいうえお"));
// array(5) { [0]=> string(3) "あ" [1]=> string(3) "い" [2]=> string(3) "う" [3]=> string(3) "え" [4]=> string(3) "お" }
プリロード
OPcacheにプリロードという機能が追加されて、なんか知らんけど速くなるらしい。
OPcacheについては勉強不足です…
Password Hashing Registry
password_hash() や password_verify() で使われるアルゴリズムを動的に追加することが可能になります。今までは常に使用できる bcrypt と、PHPコンパイル時に libargon が使用可能であれば argon2i、argon2id が使用できると言う状態でしたが、PHP7.4からはサードパーティがアルゴリズムを追加できます。
これに合わせて、拡張機能の Sodium が argon2i、argon2id のアルゴリズムをサポートしました。libargon が存在しない場合でも、Sodium があれば argon2i、argon2id が使用できるようになります。
シリアライズ用のマジックメソッドの追加
Serializable が将来的に削除されるとのこと。PHP7.4からサポートされる __serialize() と __unserialize() マジックメソッドに置きかわり、お役御免となるようです。
おわり
結構変更が多いですね。PHP7.4のリリース日は2019/11/28とのことです。
例によって僕が理解できる範囲のことしかピックアップしてないので詳しく知りたい方は以下へどうぞ。
Migrating from PHP 7.3.x to PHP 7.4.x