はじめに
こんにちは。
GMOアドマーケティングのKONCEです。
定期的にPHPバージョンアップ調査を行うのが恒例となってきました。
今回はPHP7.4のマイグレーションに関して掻い摘んで紹介します。
過去記事はこちら↓
(引用元|https://secure.php.net/download-logos.php)
目次
- PHP7.4に関して
- 新機能
2-1. 型付きプロパティ
2-2. アロー関数
2-3. Nullの場合の代入演算子
2-4. 配列内での値のアンパック - 下位互換性のない変更点
3-1. 配列でない値を配列スタイルでアクセスした場合
3-2. get_declared_classes()関数
3-3. fnキーワード
3-4. ファイルの最後の <?php タグ
3-5. パスワードアルゴリズムの定数
3-6. htmlentities()関数 - 推奨されなくなる機能
4-1. 明示的に括弧で囲わずに三項演算子をネストする
4-2. 波括弧を使った、配列や文字列のオフセットへのアクセス
4-3. (real) によるキャストと is_real() 関数
4-4. 親クラスがない場合における parent キーワードの利用
4-5. Implode 関数の、歴史的なパラメータ順序 - 最後に
PHP7.4に関して
PHP Version 7.4.0は2019年11月28日にリリースされました。
執筆日時点ではVersion 7.4.3までリリースされており、いくつかのバグフィックスがなされているようです。
プロパティ型指定が今回の変更のメインのようです。
その他下位互換性のない変更点, 推奨されなくなる機能に関しても前回同様バージョンでの挙動の差異を見ていければと思います。
新機能
型付きプロパティ
クラスのプロパティは、新たに型宣言をサポートするようになりました。
$user->id には integer の 値だけを、そして $user->name には string の値だけを代入できるように強制します。
と、公式にはありますが、厳密にはstrict_typesを指定しないと自動型変換の影響を受けるようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?php class User { public int $id; public string $name; // デフォルト値の指定ができます public float $num = 3.14; public string $text = 'Hello World'; } // 継承子クラスで型の変更はできません //class Sub extends User { // public string $id; // PHP Fatal error: Type of Sub::$id must be int (as in class User) //} $user = new User(); // 初期化してないとエラー //var_dump($user->id); // PHP Fatal error: Uncaught Error: Typed property User::$id must not be accessed before initialization //var_dump($user->name); // PHP Fatal error: Uncaught Error: Typed property User::$name must not be accessed before initialization var_dump($user->num); // float(3.14) var_dump($user->text); // string(11) "Hello World" $user->id = 1; $user->name = '1'; var_dump($user->id); // int(1) var_dump($user->name); // string(1) "1" // strict_typesを指定しないと自動型変換の影響を受けます $user->id = '1'; $user->name = 1; var_dump($user->id); // int(1) var_dump($user->name); // string(1) "1" $user->id = 'test'; $user->name = true; var_dump($user->id); // PHP Fatal error: Uncaught TypeError: Typed property User::$id must be int, string used var_dump($user->name); // string(1) "1" |
アロー関数
ちょっとした関数を記述するのが楽になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?php $factor = 10; // アロー関数 $fn1 = fn($n) => $n * $factor; // 以下と同じ $fn2 = function ($m) use ($factor) { return $m * $factor; }; var_dump($fn1(10)); //int(100) var_dump($fn2(10)); //int(100) var_dump($factor); //int(10) $array = [1, 2, 3, 4]; var_dump(array_map($fn1, $array)); //array(4) { // [0]=> // int(10) // [1]=> // int(20) // [2]=> // int(30) // [3]=> // int(40) //} var_dump(array_map($fn2, $array)); //array(4) { // [0]=> // int(10) // [1]=> // int(20) // [2]=> // int(30) // [3]=> // int(40) //} |
Nullの場合の代入演算子
変数がnull、未定義の際演算子「??=」の後ろの値になります。
手っ取り早く初期化が行えそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $array = [ null, 'hello', ]; foreach ($array as $row) { $row ??= 'World'; var_dump($row); } //string(5) "World" //string(5) "hello" |
配列内での値のアンパック
可変長引数などで使用できた引数アンパックですが、配列内でも使えるようになり、array_mergeを使用しなくても手っ取り早く配列を結合できそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php $num1 = [1, 2, 3, 4]; $num2 = 10; var_dump(array_merge($num1, [$num2])); //array(5) { // [0]=> // int(1) // [1]=> // int(2) // [2]=> // int(3) // [3]=> // int(4) // [4]=> // int(10) //} var_dump([...$num1, $num2]); //array(5) { // [0]=> // int(1) // [1]=> // int(2) // [2]=> // int(3) // [3]=> // int(4) // [4]=> // int(10) //} $parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon']; var_dump($fruits); //array(5) { // [0]=> // string(6) "banana" // [1]=> // string(6) "orange" // [2]=> // string(5) "apple" // [3]=> // string(4) "pear" // [4]=> // string(10) "watermelon" //} |
下位互換性のない変更点
配列でない値を配列スタイルでアクセスした場合
null, bool, int, float, resource型の変数に対して、配列としてアクセスしようとするとエラーが発生します。
1 2 3 4 5 6 7 8 9 10 |
<?php $null = null; $null['key']; var_dump($null); // 7.3環境 // NULL // 7.4環境 // PHP Notice: Trying to access array offset on value of type null |
get_declared_classes()関数
定義済のクラスの名前を配列として返す関数get_declared_classes()が、インスタンス化されていない無名クラスを返さなくなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php $class1 = new class {}; var_dump(count(get_declared_classes())); $class2 = new class {}; var_dump(count(get_declared_classes())); // 7.3環境(定義済みクラスの数は環境によって差異があります) // int(186) // int(186) // 7.4環境 // int(185) // int(186) |
fnキーワード
上記新機能アロー関数に伴い「fn」が予約語となり、関数名、クラス名として使用できなくなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php function fn() {}; // 7.4環境 // PHP Parse error: syntax error, unexpected 'fn' (T_FN), expecting '(' class fn { } // 7.4環境 // PHP Parse error: syntax error, unexpected 'fn' (T_FN), expecting identifier (T_STRING) |
ファイルの最後の <?php タグ
ファイル最終行に改行がない場合でも <?php が開始タグとして解釈されるようになります。これまでは文字列として解釈されていました。
7.3環境では <?php と出力されます。開始タグだけのファイル用意したことないけど。
1 |
<?php |
パスワードアルゴリズムの定数
パスワードハッシュのアルゴリズムの識別子の定数が、数値型からnullableな文字列型に変更になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php var_dump(PASSWORD_DEFAULT); var_dump(PASSWORD_BCRYPT); var_dump(PASSWORD_ARGON2I); var_dump(PASSWORD_ARGON2ID); // 7.3環境 // int(1) // int(1) // int(2) // int(3) // 7.4環境 // string(2) "2y" // string(2) "2y" // string(7) "argon2i" // string(8) "argon2id" |
htmlentities()関数
htmlentities()関数がUTF-8以外のマルチバイトエンコーディングでは、基本的なエンティティの置換のみがサポートしているエンコーディングで使われた場合、E_NOTICEを発生するようになります。
1 2 3 4 5 |
<?php htmlentities('test', ENT_QUOTES, 'Shift_JIS'); // PHP Notice: htmlentities(): Only basic entities substitution is supported for multi-byte encodings other than UTF-8; functionality is equivalent to htmlspecialchars |
推奨されなくなる機能
明示的に括弧で囲わずに三項演算子をネストする
三項演算子の記述を一意にしないとdeprecatedが発生するようになりました。ややこしい書き方すんなって僕でも思います。
1 2 3 4 5 |
<?php 1 ? 2 : 3 ? 4 : 5; // PHP Deprecated: Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` (1 ? 2 : 3) ? 4 : 5; // ok 1 ? 2 : (3 ? 4 : 5); // ok |
波括弧を使った、配列や文字列のオフセットへのアクセス
{}を使用しての配列や文字列にアクセスするとdeprecatedが発生するようになりました。これまでは出ていませんでした。
1 2 3 4 5 6 7 8 9 |
<?php $array = [1, 2, 3, 4, 5]; $string = '12345'; var_dump($array[2]); var_dump($string[2]); var_dump($array{2}); // PHP Deprecated: Array and string offset access syntax with curly braces is deprecated var_dump($string{2}); // PHP Deprecated: Array and string offset access syntax with curly braces is deprecated |
(real) によるキャストと is_real() 関数
(real)によるキャスト、is_float()関数のエイリアスis_real()関数が共にdeprecatedが発生するようになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php $test = 1; var_dump((real)$test); // PHP Deprecated: The (real) cast is deprecated, use (float) instead var_dump((float)$test); var_dump(is_real($test)); var_dump(is_float($test)); // PHP Deprecated: Function is_real() is deprecated // float(1) // float(1) // bool(false) // bool(false) |
親クラスがない場合における parent キーワードの利用
メソッドの呼び出し有無に関わらず、親クラスがない場合にparentキーワードを利用すると、deprecatedが発生するようになりました。
以前の環境でも呼び出せばエラーが発生していました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php class Test { public function foo() { return parent::foo(); } } // PHP Deprecated: Cannot use "parent" when current class scope has no parent // 7.3環境 $obj = new Test(); $obj->foo(); // PHP Fatal error: Uncaught Error: Cannot access parent:: when current class scope has no parent |
Implode 関数の、歴史的なパラメータ順序
配列要素を文字列により連結するimplode()関数では引数の順番を変更しても動作する状況でしたが、PHP7.4でdeprecatedが発生するようになりました。
コーディングルールが一つ減ったくらいの感覚です。
1 2 3 4 5 6 7 8 9 |
<?php $array = [1, 2, 3, 4, 5]; var_dump(implode(':', $array)); var_dump(implode($array, ':')); // PHP Deprecated: implode(): Passing glue string after array is deprecated. Swap the parameters // string(9) "1:2:3:4:5" // string(9) "1:2:3:4:5" |
最後に
執筆する際毎度のように同じような感想になってしまいますが、今回のPHP7.4は型付きプロパティなど試したい新機能もあり、調査を行ってよかったと思えました。
今後もPHPの情報をキャッチアップして、発信できていければと思います。
GMOアドマーケティングではエンジニアを募集しています。
興味がある方は以下のページをご覧ください。
■エンジニア採用ページ ~福利厚生や各種制度のご案内はこちら~