RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

PHP8.1 の新機能について語り合う・前編【PHP TechCafe イベントレポート】

f:id:tech-rakus:20210914155822p:plain

弊社で毎月開催し、PHPエンジニアの間で好評いただいているPHP TechCafe。2021年8月のイベントでは社外でご活躍されているPHPエンジニアにもご参加いただいて「PHP8.1の新機能」について語り合いました。

rakus.connpass.com

PHP8.1の新機能は8.0に比べれば少ないとはいえ、順番に追いかけてみると思ったより大きなボリュームになったためイベント内容を2回に分けてレポートします。今回は前編として前半の半分をご紹介します。

PHP8.1 新機能について

PHP8.1の新機能は弊社のメンバーが事前にShowNoteにまとめていました。今回はこれに従って新機能をみていきました。

hackmd.io

Enums

複数の定数をまとめる「列挙型」がサポートされるようになりました。「昔から話としては上がっていたが、ついに正式に実装されます。」と紹介されて、8.1の中でも特に大きく取り上げられています。

ここではまず以下のようなコードを使って解説されました。

Enumの書き方

<?php

enum CardsMark
{
    case DIAMOND;
    case HEART;
    case SPADE;
    case CLOVER;
}

Enumの実装例

<?php

class Card
{
    public function __construct(
        public CardsMark $mark, 
    ) {}
}

$card = new Card(CardsMark::DIAMOND);

この例をもとに、Enumを使うことで以下のような実装ができると説明がありました。

  • コンストラクタで引数を持つときにEnumのカードマークに適しているものしか受け付けないようなクラスをつくることが出来る
  • オブジェクト作るときにはカードマークを付けてオブジェクトを作る形にできる
  • (上記の例のCardクラスのように)入ってくる値がEnumで列挙されたものに固定されるので、意図しないものが入ってくることを防げる

また、以下のような特徴も紹介されました。

  • 定数をまとめるだけじゃなくて、メソッドも定義できる
  • インターフェイスを実装することもできる
  • (上記のCardsMarkのような)存在するパターンを実装したEnumですよという書き方ができる

意図しない実装を防ぎ、意図が伝わりやすい実装になるというコメントが紹介されました。

Enumの実現は10年以上かかった

基礎知識の解説のあとはEnumPHPの機能に追加されるまでの歴史的背景の話題で盛り上がりました。

  • Enumは2010年頃から提案されていた
  • ずっと提案されていたし、ユーザからも色々あった
  • どのEnum実装にするかは数あるライブラリのどれを使うか議論があった
  • PHPの内部実装的に実現が難しかった

Javaとかには普通にある機能なんですよね。はるか昔からある機能で、Effective Java みたいな『とりあえずこれ読んどけ』みたいな本には『有限要素の表現をするときにはまずEnum使え』とか書いてありましたね。」というコメントもあり、他の言語では早くから取り入れられたEnumPHPでもやっと使えるようになったことは、参加したPHPerにとっては感慨深いものがあるようでした。

※各言語で採用されているEnum(残念ながらWikipediaの列挙型のページにはまだPHPの例が掲載されていない)

ja.wikipedia.org

オフショア開発を担当しているエンジニアからは、「日本人で、しかもその時いたメンバーなら『あのときあの経緯で作ったから、ここにはこの値しか入れないよね』という暗黙の了解がいつの間にか新しいメンバーや国境を超えたメンバーには伝わってなくて、いつの間にか全く知らない値が入るようになっちゃったりして。そういう使い方のつもりじゃなかったんだ!?ってことが防げますね。」という意見もありました。

一方で、他の言語に似てきていることから「PHPらしくない」という意見もありました。Enumが導入されたことで「他の言語へ乗り換えも検討するレベルかな?」という意見も出てきましたが、大半の意見は「PHPの中で出来る方が絶対いい」「今から新しい言語に乗り換えるってなったら…」と、他の言語へ乗り換えるのは別の懸念も多く予想され消極的な様子でした。 ただし、もともとPHPで書いてたものをScalaにリプレイスしたサービスの事例が取り上げられ、「(可能性は)0%ではない」「PHPだとパフォーマンスが出しにくいので、他の言語のほうがパフォーマンスも出る」などのニーズにもよるという意見がありました。

PHPからScalaへ乗り換えたチャットワークさんの事例

チャットワークがScalaを採用する理由、これからのチャレンジ。 | チャットワーククリエーターズブログ

いずれにしても、Enumが導入されたことで「安全にかつ意図を表現できるようになった。」「喜ばしい変更ですね。」「PHPの流れに沿っていますね。」「まず使ってみて、身体を慣らしてもらえれば。」という前向きな意見が大半でした。

Fibers

Fibersという非同期処理を実行するための仕組みが導入されます。ただし、この機能によってPHPで非同期処理ができて、処理パフォーマンスが向上するかというとまだそうではないようです。1つのプロセスの中で処理を切り替えているだけなので、他の処理をブロックしてしまう機能がまだあり、同時並行で重い処理をこなすというのは現時点ではまだ難しいとRFCには書かれているようです。このあたりも、そのうちブロックされないライブラリを使ったり、コアの方もどんどん解消されていくことで理想に近づいていくのではないか、ということがRFCに書かれているようです。

  • これで夢が開けるかっていうとまだちょっと早い。もうちょっと先かな。
  • 実際に同時並列でっていうのはまだ実現できない。
  • ずっと試しているんですけどめちゃくちゃセグフォ(セグメンテーション違反)が出てですね……
  • 人によると思うんですけどいわゆる普通レベルの恩恵に預かるにはライブラリ経由で預かることになるかなと。

恩恵を受けるのはまだ先

ライブラリなどの開発向けの機能であり、一般のPHPerが恩恵を受けるにはまだ先になりそうです。 また、Fiberという名前の由来についても紹介されました。「軽量スレッドと言われていて、スレッドより細いからFiberだそうです。」とのことで、「縫い糸」という意味のスレッドより細いものということで「細長い糸」という意味のFiberが採用されたようです。

Performance improvements

パフォーマンスが約20%向上

ZendEngineのパフォーマンス向上により、ベンチマーク結果では約20%向上したそうです。大幅な進化というわけではありませんが、参加者からは以下のような意見がありました。

  • 正直天井、PHPの限界みたいなことを聞いてましたが、まだ20%上がる余地があったんですね。
  • ZendEngine自体の高速化だからなんにもしなくても恩恵を得られますよね。
  • PHPは遅い言語ではない、ということですね。

ただし、特定のベンチマークの結果なので、「全部のシチュエーションで20%向上ってわけではない」とのことです。

wiki.php.net

Array Unpacking with string keys

PHP 8.1 では文字列のキーでも配列のマージができるようになりました。書き方が変わったよという機能です。

<?php

$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]

覚えておけば得することもある書き方

ここでは今回のような「こんな書き方できたんだったな」という機能がいくつかあるよね、という話題で盛り上がりました。「こういうの出てくるたびに、覚えとかないとってなりますね。」とのことですが、一方で「どう調べたら良いかわからないですね。これはどういう意味なの?っていう。」という意見もありました。「名前が分からないとググれないですね。点々でつなげているのでググりようがない。」ということで、検索するのは難しいですが、PHPのマニュアルが親切なので配列のマニュアルをしっかり読めばわかるとのことなので、まずはマニュアルを熟読したいところです。

www.php.net

new in initializer

デフォルト引数はもともとPHPにある機能で、引数を渡されていない場合のデフォルト値を指定できますが、これまではオブジェクト指定することができませんでした。8.1からはデフォルト値に新しいオブジェクトのインスタンスを持たせることが出来るようになります。

<?php

class Test {
    public function __construct(
        private Logger $logger = new NullLogger,
    ) {}
}

「これまでは便宜的にnullとかにしておいて、nullだったらこのデフォルトのオブジェクト入れる、みたいなちょっと冗長な書き方をしていたけど、もう少し意図が分かる形で表現できるようになるし、簡潔に書けるようになる。」と、この新機能のメリットが説明されました。

一方で、上記の例では「Testクラスが NullLogger と密結合してしまうので、そういう疎結合にできなくなって無意識に結合しちゃうっていうのはあると思います。」というデメリットも紹介されました。

PHP8.0から拡張されて進化している

コンストラクタのProperty設定を引数のところで書けるというのがPHP8.0から出来るようになっています。とはいえ、このオブジェクトを初期化することができなかった課題から今回の拡張が取り入れられたようです。

「単発でも使えるけれど、Attributeの拡張みたいな側面もあって、今までAttributeの中では定数式、文字列とか、配列の中にさらに文字列等しか入っていないものしか入れてられなかったけれど、そこにオブジェクトの初期化も入れられるようになった。Attributeの入れ子みたいなことも出来るようになりますね。」と具体的な活用方法の例が紹介されました。

「PHP8でできたばかりの機能がどんどん拡張されていくスタイルなんですね。進化が目覚ましい。」と期待の声もあがっていました。

Readonly Properties

宣言後に一度だけ初期化出来るプロパティを追加できる機能です。読み取りだけ出来るプロパティを作るというのが今までなかったため、「かゆいところに手が届く」と紹介されました。ただし、型付のプロパティのみ使用可能という条件付きです。型がついていないプロパティの初期値がNullになってそこから変更できないため、それはできないとのことです。

ここでは「もとからfinalを使ったら駄目なのか?」という疑問点もあがりました。これに対しては、「finalはメソッドでも使えるもので、上書きできないという意味なので、final使うとプロパティの定義を上書きできないというふうに誤読できてしまう。」と、finalの使い方とreadonlyの使い方の違いが解説されました。

今まではPHPDocなどに頼っていた

Readonly Propertiesは「8.1の変更の中で使い所の多そうなものの一つ」と活用シーンが多そうな期待の声があがっていました。

「今まではPHPDocに @property-read って書くことで読み取る専用というのを書いたりしてましたね。」と過去のやりかたが紹介されました。これまではPHPDocなどの別の方法で実現していたことが、PHPの言語仕様で実現できるようになります。「自分のプロパティ内でも書き込みができない、上書きができないってことなのでimmutableなClassが作りやすくなります。」と活用シーンの期待が説明されました。

First-class Callable Syntax

クロージャーを作るときに ... を書くだけで作れるようになります。

<?php

function foo(int $a, int $b) { /* … */ }

$foo = foo(...);

$foo(a: 1, b: 2);

引数を受け取るようになっていたときにクロージャーが作れるようになります。

前述のArray Unpackingの書き方と似ているので、「読み慣れないうちは見間違えるんじゃないかという意見もあるようです。」と懸念が紹介されました。

静的解析が可能になる

読みづらそうだし、使い方がイメージしづらい懸念の声がありましたが、メリットとして上記のコードの例をもとに次のように解説されました。

  • 今までは文字列のfooっていうのを書いたりしなきゃいけなかったけど、野暮ったいし静的解析できない
  • ちゃんと静的に書けるようになったのが嬉しいですね。
  • 例えばArrayマップとかで助かる

静的解析が可能な書き方になるのがポイントのようです。

後編へ続く

PHP8.1の新機能はまだまだあります。後編では以下についてご紹介します。

  • Pure intersection Types
  • New never type
  • New Array_is_list_function
  • final class constants
  • New fsync function
  • Explisit octal integerliteral notation
  • Restrict $GLOBALS usage

後編をお楽しみに!


  • エンジニア中途採用サイト
    ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
    ご興味ありましたら是非ご確認をお願いします。
    20210916153018
    https://career-recruit.rakus.co.jp/career_engineer/

  • カジュアル面談お申込みフォーム
    どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
    以下フォームよりお申込みください。
    forms.gle

  • イベント情報
    会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.