PHPの知識が7.3から止まっているので8.1までの新機能を駆け足でキャッチアップする。
<?php
    class Person {
        public int $age; // 指定の型だけ代入できるように強制される
        public string $name;
    }
?>
<?php
// これが
$a = 1
$func_7_3 = function($b) use ($a) {
    return $a + $b;
}
echo $func_7_3(1); // 2
// 7.4からはこのように書ける
$func_7_4 = fn($b) => $a + $b; // 暗黙的な値スコープを持つ
echo $func_7_4(1); // 2
?>
<?php
// これが
$name = isset($name) $name : getName();
// 7.4からはこのように書ける
$name ??= getName();
?>
<?php
$values = ['a', 'b'];
$all = [...$values, 'c']; // a, b, c
?>
PHPから別言語を呼び出せる。
Goのcgoみたいなやつ。
opcacheにスクリプトを事前ロードする機能が追加された。
// php.ini
opcache.preload=preload.php
<?php
function namedFunc($foo, $bar, $baz) {
  echo $foo . $bar . $baz;
}
// 引数の順番は関係なく、名前付きで引数をセットできる
namedFunc(baz: "baz", foo: 'foo', bar: "bar"); // bazfoobar
?>
アノテーションの新機能。
<?php
#[Attribute]
class Person
{
  public $name;
  public function __construct($name)
  {
    $this->name = $name;
  }
}
#[Person(name: "John")]
class Man
{
}
// Reflection APIでアトリビュートにアクセスできる
function output($reflection) {
  foreach ($reflection->getAttributes() as $attribute) {
    var_dump($attribute->getName());
    var_dump($attribute->getArguments());
    var_dump($attribute->newInstance());
  }
}
output(new ReflectionClass(Man::class));
// string(6) "Person"
// array(1) {
//   'name' =>
//   string(4) "John"
// }
// class Person#3 (1) {
//   public $name =>
//   string(4) "John"
// }
?>
引数、戻り地、プロパティに対してunion型を宣言できるようになった。
<?php
function unionFunc(int|string $value): int|string
  return $value;
}
unionFunc(1);
unionFunc("Hello World");
?>
<?php
function matchFunc($value) {
    // switch文とは異なり、厳密な比較(===)となる
    return match($value) {
        "one" => 1,
        "two" => 2,
        "three" => 3,
    };
};
echo matchFunc("one"); // 1
?>
null安全なコードが書きやすくなる。
<?php
class User
{
  public $name;
  public function __construct()
  {
    $this->name = $name;
  }
  public function getName()
  {
    return $this->name;
  }
}
class Account
{
  public User|null $user = null;
}
$account = new Account();
// $account->user->getName(); // PHP Fatal error:  Uncaught Error: Call to a member function getName() on null
$account->user?->getName();
?>
<?php
    $a1 = ["a" => 1];
    $a2 = ["a" => 2];
    var_dump(["a"=>0, ...$a1, ...$a2]); // ["a" => 2] キーは後勝ちになるっぽい。
?>
<?php
enum ColorCode: string
{
  case BLUE = "#0000ff";
  case YELLOW = "#ffff00";
  case RED = "#ff0000";
}
function enumFunc(ColorCode $color) {
  echo $color->name; 
  echo $color->value; 
}
enumFunc(ColorCode::BLUE); // BLUE blue
// enumFunc("green"); // PHP Fatal error:  Uncaught TypeError: enumFunc(): Argument #1 ($color) must be of type ColorCode, string given
?>
完全なスタックを持つ、停止可能な関数。コールスタックのどこからでも停止・再開が可能。
非同期処理が書ける。
unionが型のORなら、交差型は型のAND。
<?php
function check(Foo&Bar $intersection)
{
  return;
}
class Foo{}
class Bar{}
class Baz{}
$foo = new Foo();
$foo->check(new Foo());
$foo->check(new Bar());
// $foo->check(new Baz()); // PHP Fatal error:  Uncaught Error: Call to undefined method Foo::check() 
?>
戻り値にのみ指定できる型。関数がexit()するか例外を投げるか終了しないかを示す。
voidとは違う。
どんどん型を意識したコードが書きやすくなってきている印象。
下位互換性は流し読みしかしていないのでアプデ対応のときでも再度読み直したい。
関連書籍