PHP8-新機能を試す



PHP 8はすでにリリース候補段階にあり、バージョンRC 3は10月29日にリリースされ、完全リリースは11月26日に予定されています。それでは、PHP8で私たちを待っている新機能を見てみましょう。リリーススケジュールはここで確認できますそして、新しいバージョンに更新するための公式ガイドはここにあります



ユニオンタイプのサポートが追加されました(RFC



ユニオンタイプは、1つだけでなく、他のさまざまなタイプの値を受け入れます。



<?php
declare(strict_types=1);
 
class Number {
    private int|float $number;
 
    public function setNumber(int|float $number): void {
        $this->number = $number;
    }
 
    public function getNumber(): int|float {
        return $this->number;
    }
}
 
/**
 * We can pass both floats or integer values
 * to the number object. Try passing a string.
 */
$number = new Number();
 
$number->setNumber(5);
 
dump($number->getNumber());
 
$number->setNumber(11.54);
 
dump($number->getNumber());
 
exit;


WeakMap(RFC)を追加しました



弱いマップを使用すると、オブジェクトと任意の値(および)の間に関係を作成できますがSplObjectStorage、キーとして使用されるオブジェクトはガベージコレクターから保護されません。コレクターがそのようなオブジェクトを破壊した場合、それは単にマップから削除されます。


これは非常に便利な機能です。これにより、コード内のメモリリークについて考えることがさらに少なくなります。これはほとんどのPHP開発者にとって問題にはならないはずですが、たとえばReactPHPを使用して、長時間実行されるプロセスを作成する場合は検討する価値があります。WeakMapsを使用すると、オブジェクトが使用できなくなったときに、オブジェクト参照がガベージコレクターによって自動的に収集されます。



配列で同じことを行うと、オブジェクト参照が存続し、メモリリークが発生します。



<?php
declare(strict_types=1);
 
class FooBar {
    public WeakMap $cache;
    
    public function __construct() {
      $this->cache = new WeakMap();
    }
 
    public function getSomethingWithCaching(object $obj) {
        return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj);
    }
    
    public function computeSomethingExpensive(object $obj) {
    dump("I got called");
    return rand(1, 100);
    }
}
 
$cacheObject = new stdClass;
 
$obj = new FooBar;
// "I got called" only will be printed once
$obj->getSomethingWithCaching($cacheObject);
$obj->getSomethingWithCaching($cacheObject);
 
dump(count($obj->cache));
 
// When unsetting our object, the WeakMap frees up memory
unset($cacheObject);
 
dump(count($obj->cache));
 
exit;


新しい例外ValueError



PHP 8では、新しい組み込みの例外クラスが導入されていますValueErrorそれはそれ自体を補完します\ExceptionPHPは、正しい型の値を関数に渡すたびにこの例外をスローしますが、この操作では使用できません。以前は、このような場合に警告が発行されていました。例:



<?php
declare(strict_types=1);
 
/**
 * We pass an array to array_rand,
 * which is of the correct type. But
 * array_rand expects non-empty arrays.
 *
 * This throws a ValueError exception.
 */
array_rand([], 0);
 
/**
 * The depth argument for json_decode is a
 * valid integer, but it must be greater than 0
 */
json_decode('{}', true, -1);


関数を定義するときは、さまざまな引数を使用できます



タイプに互換性がある場合は、任意の数の関数パラメーターをvariadic引数に置き換えることができるようになりました。たとえば、次のコードは正しくありません。


<?php
declare(strict_types=1);
 
class A {
    public function method(int $many, string $parameters, $here) {
 
    }
}
class B extends A {
    public function method(...$everything) {
        dd($everything);
    }
}
 
$b = new B();
$b->method('i can be overwritten!');
exit;


戻り型静的(RFC



静的リターンタイプを使用して、メソッドが継承された場合でも、メソッドが呼び出されたクラスを返すかどうかを判断できるようになりました(後期静的バインディング)。



<?php
declare(strict_types=1);
 
class Test {
    public function doWhatever(): static {
        // Do whatever.
        return $this;
    }
}
 
exit;


オブジェクトクラス名リテラル(RFC



これで、を使用してオブジェクトのクラス名を取得できます$object::class結果はと同じになりget_class($object)ます。



<?php
declare(strict_types=1);
 
auth()->loginUsingId(1);
 
dump(auth()->user()::class);
 
// Or with a temporary variable
$user = auth()->user();
 
dump($user::class);
exit;


可変構文設定(RFC



Newそしてinstanceof、任意の式で使用できるようになりました:new ()(...$args)および$obj instanceof ()



<?php
declare(strict_types=1);
 
class Foo {}
class Bar {}
 
 
$class = new (collect(['Foo', 'Bar'])->random());
 
dd($class);
 
exit;


ストリング可能なインターフェース(RFC



PHP 8では、Stringableクラスがメソッドを実装するとすぐに自動的に追加される新しいインターフェイス導入されています__toStringこのインターフェイスを明示的に実装する必要はありません。



<?php
declare(strict_types=1);
 
class Foo {
    public function __toString() {
        return 'I am a class';
    }
}
 
$obj = new Foo;
dump($obj instanceof Stringable);
 
exit;


トレイトで抽象的なプライベートメソッド(RFC)を定義できるようになりました



<?php
declare(strict_types=1);
 
 
trait MyTrait {
    abstract private function neededByTheTrait(): string;
 
    public function doSomething() {
        return strlen($this->neededByTheTrait());
    }
}
 
class TraitUser {
    use MyTrait;
 
    // This is allowed:
    private function neededByTheTrait(): string { }
 
    // This is forbidden (incorrect return type)
    // private function neededByTheTrait(): stdClass { }
 
    // This is forbidden (non-static changed to static)
    // private static function neededByTheTrait(): string { }
}
 
exit;


throwを式として使用できるようになりました(RFC



throwは、のみが許可されている場合に使用できるようになりました。矢印関数、合体演算子、3値条件演算子(3値/エルビス)。



<?php
declare(strict_types=1);
 
$callable = fn() => throw new Exception();
 
$nullableValue = null;
 
// $value is non-nullable.
$value = $nullableValue ?? throw new \InvalidArgumentException();
 
 
exit;


オプションのハンギングコンマ(RFC)がリストパラメータで許可されるようになりました



配列のぶら下がっているコンマと同様に、リストパラメータで定義できるようになりました。



<?php
declare(strict_types=1);
 
function method_with_many_arguments(
    $a, 
    $b,
    $c,
    $d,
) {
    dump("this is valid syntax");
}
 
method_with_many_arguments(
    1,
    2,
    3,
    4,
);
 
exit;


変数に格納せずに例外をキャッチする(RFC



これcatch ()で、例外を変数に格納せずに、例外をキャッチするように書き込むことができます。



<?php
declare(strict_types=1);
 
$nullableValue = null;
 
try {
    $value = $nullableValue ?? throw new \InvalidArgumentException();
} catch (\InvalidArgumentException) {
    dump("Something went wrong");
}
 
 
exit;


混合(RFC)タイプのサポートが追加されました



PHP 8では、mixedと呼ばれる新しいタイプが導入されています。これは、タイプarray、bool、callable、int、float、null、object、resource、stringと同等にすることができます。



<?php
declare(strict_types=1);
 
function debug_function(mixed ...$data) {
    dump($data);
}
 
debug_function(1, 'string', []);
 
exit;


属性のサポートが追加されました



PHP8で属性を実装するためのいくつかの提案があります。





これは、PHP 8の最大の変更点の1つです。最初は、簡単に理解できない場合があります。つまり、属性を使用すると、PHPの関数、パラメーター、クラスなどにメタデータを追加できます。このメタデータは、プログラムで取得できます。PHP 7以下で時計を解析する必要がある場合、属性はPHP自体に深く統合されたこの情報にアクセスするのに役立ちます。



明確にするために、ユーザーが属性を使用してクラスまたはメソッドコントローラーにミドルウェアを追加できるようにしたいとします。



<?php
declare(strict_types=1);
// First, we need to define the attribute. An Attribute itself is just a plain PHP class, that is annotated as an Attribute itself.
 
#[Attribute]
class ApplyMiddleware
{
    public array $middleware = [];
 
    public function __construct(...$middleware) {
        $this->middleware = $middleware;
    }
}
 
// This adds the attribute to the MyController class, with the "auth" middleware as an argument.
 
#[ApplyMiddleware('auth')]
class MyController
{
    public function index() {}
}
 
// We can then retrieve all ApplyMiddleware attributes on our class using reflection
// And read the given middleware arguments.
 
$reflectionClass = new ReflectionClass(MyController::class);
 
$attributes = $reflectionClass->getAttributes(ApplyMiddleware::class);
 
foreach ($attributes as $attribute) {
    $middlewareAttribute = $attribute->newInstance();
    dump($middlewareAttribute->middleware);
}
 
exit;


コンストラクタープロパティの転送(RFC)のサポートが追加されました



コンストラクターをプロパティ定義と組み合わせることができる簡単な構文を追加することをお勧めします。



<?php
declare(strict_types=1);
 
class User {
    public function __construct(
        public int $id,
        public string $name,
    ) {}
}
 
$user = new User(1, 'Marcel');
 
dump($user->id);
dump($user->name);
 
exit;


一致式のサポートが追加されました(RFC



より安全なセマンティクスと値を返す機能のみを備えた、match類似し た新しい式を追加することが提案されましたswitch



<?php
declare(strict_types=1);
 
echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};
 
exit;


nullsafe演算子のサポートが追加されました(?->)(RFC



演算子の左側の結果がnullの場合、チェーン全体の実行が停止され、その結果がnullに設定されます。それ以外の場合、チェーンは通常の演算子のように動作し->ます。


<?php
declare(strict_types=1);
 
class User {
    public function getAddress() {}
}
 
$user = new User();
 
$country = $user?->getAddress()?->country?->iso_code;
 
dump($country);
 
exit;


名前付き引数(RFC)のサポートが追加されました



名前を付けると、パラメータの位置ではなく、名前に基づいて関数に引数を渡すことができます。つまり、引数の値は自己文書化され、引数は列挙順序に依存しなくなるため、デフォルト値を任意にスキップできます。


<?php
declare(strict_types=1);
 
array_fill(start_index: 0, num: 100, value: 50);
 
exit;



All Articles