PHP 7.4 新機能解説 PHP コア編

php74_release

2019年11月28日、PHP7.4.0がリリースされました!

https://www.php.net/archive/2019.php#2019-11-28-1

公式ドキュメントで発表された新機能のうち、この記事ではPHPコア部分の機能について詳しくみていきたいとおもいます✨

※ 各コードは公式ドキュメントから引用の上、一部編集しています。

型付きプロパティ

クラスのプロパティに、型を宣言できるようになりました。

プロパティの型宣言
class User {
    public int $id;
    public string $name;
}

宣言した型以外の値を代入しようとすると、エラーが教えてくれます。

宣言ありプロパティへの代入
$user = new User();
$user->id = 2; // エラーなし
$user->id = 'test'; // Fatal error: Uncaught TypeError: Typed property User::$id must be int, string used in...

これまで通りに宣言なしでも動くので、上手く使い分けていきたいですね!

型宣言なし
// これも動く
class User {
    public $id;
    public $name;
}

個人的には、宣言するのを基本として、動的型付けをしたいプロパティだけ宣言なしにするのが良いとこ取りできて良いのではと思っています。

アロー関数

アロー関数は、ざっくり言うと”function”を記述せずに関数を定義できる書き方です。

基本の関数定義
function 関数名(引数) {
  処理
} 
アロー関数定義
fn(引数) => 処理

例えば、コールバック関数を指定すべきところにこのアロー関数を使うと大幅にコード量を減らすことができます。

従来の書き方
function cube($n)
{
    return($n * $n * $n);
}
$a = array(1, 2, 3, 4, 5);
$b = array_map("cube", $a);
print_r($b);
アロー関数を使った書き方
$a = array(1, 2, 3, 4, 5);
$b = array_map(fn($n) => $n * $n * $n, $a);
print_r($b);

結果はどちらの書き方でも変わらず、以下のようになります。

出力結果
Array
(
    [0] => 1
    [1] => 8
    [2] => 27
    [3] => 64
    [4] => 125
)

返り値の型を狭めたり、引数の型を広げたりする

型の変位指定が行えるようになりました。

返り値の型を狭める例
<?php
class Water {}
class Wine extends Water {}

class Glass {
    public function pour(): Water {}
}
class WineGlass extends Glass {
    public function pour(): Wine {}
}

WineクラスはWaterクラスを継承しているので、型の広さはWater > Wineとなります。

従来であれば、WineGlassクラスのpour()メソッドではGlassクラスのpour()メソッドと同じ返り値の型を指定する必要がありましたがが、PHP7.4 からは型を狭めることができるようになったので、上記のコードが成り立つようになりました。

私もまだ 変位指定についての知識が浅いので、使いどころ等詳しいことが分かり次第また更新したいと思います(参考文献などございましたら、 @muchoco_dev 宛に教えていただけると大変嬉しいです!)。

Nullの場合の代入演算子

「値がNullの場合、とある値を代入する」という処理が日常的に行われているかと思いますが、代入演算子を使って1行で書くことができるようになりました!

従来の書き方
if (!isset($array['key'])) {
    $array['key'] = 1;
}
新しい代入演算子を使った書き方
$array['key'] ??= 1;

これは地味に嬉しい……。

今後使う人が増えると予想されるので、コードリーディングのときに「これなんだっけ?」とならないようにしっかりと覚えておきたいです。

配列内での値のアンパック

配列の任意の場所に、別の配列の要素をまとめて追加できるようになりました。

配列内で別の配列を展開
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];

// $fruitsの中身
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

上の例のように、別の配列の要素を追加したい場所に「…(ドット3つ)」と変数名を記入するだけで、中身を展開して追加してくれます。

便利かつ直感的に分かりやすい記法ですね!

数値リテラルのセパレータ

数値の間にアンダースコアを挿入できるようになりました。

アンダースコアを挿入した各数値の例
6.674_083e-11; // float
299_792_458;   // decimal
0xCAFE_F00D;   // hexadecimal
0b0101_1111;   // binary

内部ではアンダースコアがないものと同等に扱われ、おそらく人間が見やすくするためのものだと思います。

var_dump(299_792_458);
// int(299792458)

弱参照

弱参照のWeakReferenceクラスを使えるようになりました。弱参照を使用することで、 オブジェクトの破棄を防がない参照を保持することができます。

https://www.php.net/manual/ja/class.weakreference.php

例えば次のように使用します。

WeakReferenceクラスを利用した弱参照の例
$obj = new stdClass;
$weakref = WeakReference::create($obj);
var_dump($weakref->get());    // object(stdClass)#1 (0) { }
unset($obj);
var_dump($weakref->get());    // NULL

このコードは、下記のような処理を行っています。

$weakref = WeakReference::create($obj);

$objの新しい弱参照を作成の上、$weakrefに代入。

$weakref->get(); 

弱参照されたオブジェクトを取得。

unset($obj);

$objを破棄。

弱参照は既に他のいくつかの言語でサポートされており、主にキャッシュモジュールの実装などに活用されています。PHPでも今後同様に活用されていくことと思われます。

__toString()から例外をスロー可能に

__toString()メソッドは、クラスが文字列に変換される際の動作を定めるマジックメソッドです。

https://www.php.net/manual/ja/language.oop5.magic.php

__toString()の利用例
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$class = new TestClass('Hello');
echo $class;
出力結果
Hello

$classはTestClassオブジェクトが代入されていますが、文字列として扱われた場合は__toString()メソッドでコンストラクタの引数として受け取った値を返すと定義してあるので、Helloが出力されます。

ただし、これまでは__toString()メソッド内で例外をスローすることはできないという制限があり、次のようなコードでは致命的なエラーが発生していました。

__toString()メソッド内で例外をスロー
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        if (!$this->foo) {
            throw new Exception('文字列が空です');
        }
        return $this->foo;
    }
}

$class = new TestClass('');
try {
    echo $class;
} catch(Exception $e) {
    echo $e->getMessage();
}
従来の結果(Fatal error)
Fatal error: Method TestClass::__toString() must not throw an exception, caught Exception: 文字列が空です in ...

この制限がPHP7.4からはなくなり、上記のような例外処理つきコードが動くようになりました。

PHP7.4以降の結果
文字列が空です

以上が、PHP7.4のPHPコアに関するアップデート内容です。