Page 1
PHPは何を捨て、
どんな力を手に入れてきたのか
What did PHP give up and what power did it get?
PHP Conference Japan
2019-12-01 #phpcon
公開日:
by USAMI Kenta@tadsan
に東京都大田区蒲田の大田区産業プラザ PiOで開催された『PHPカンファレンス2019』でレギュラーセッション(25分)として発表しました。
What did PHP give up and what power did it get?
PHP Conference Japan
2019-12-01 #phpcon
これまでのあらすじ
昨日
そもそもPHP自体がレガシーと言われがち
PHPカンファレンス2016
本日のお題
そもそもPHPというプログラミング言語はどんな機能を持っているのか
“We have things like protected properties.We have abstract methods. We have all this stuff that your computer science teacher told you you should be using.I don't care about this crap at all.”
–Rasmus Lerdorf https://en.wikiquote.org/wiki/Rasmus_Lerdorf
“PHPにはprotectedプロパティも抽象メソッドもありますよ。計算機科学の教授が「使え」と言ってるものは全部。そんなことはクソ興味ないですけど”–Rasmus Lerdorf
僕が思いつくPHPの機能をざっと挙げてみると…
抽象クラス, トレイト, インターフェイス, ジェネレータ, イテレータ, クロージャ, 函数の動的呼び出し, 無名クラス, eval, 型宣言, 連想配列, リフレクションAPI, 自己文書化, 標準入出力の読み書き,REPL, クラスの遅延ロード
改めてPHPの言語仕様が追加された時系列を見てみよう
Arrow functions 2.0
JavaScriptなど
Typed Property
Javaなどの静的型付き言語
Numeric Literal Separator
Ada, Ruby, JavaScriptなど
Flexible Heredoc and Nowdoc
Rubyにも似た記法はある
list() Reference Assignment
これはPHP独自に近い
Trailing Commas In List Syntax
カンマ(,)を並べて書く記法のほぼ全てで余分につけてもよくなった
Parameter Type Widening
継承したクラスで引数の型省略
Nullable Types
Void Return Type
Multi catch
Allow specifying keys in list()
Anonymous Class
Generator Delegation(yield from)
Return Type Declaration
Null Coalesce Operator
Scalar type hints
Exponential Operator(pow**)
Importing named function
Variadic function argument (...)
配列を引数として展開
Argument unpacking(...)
可変長引数を配列として取得
Generator
finally keyword (try-catch-...)
Const array/string dereference
Allow non-scalar keys in foreach
Traits
Short array syntax
callable type hint
Closures (function expression)
関数式、クロージャ、またはラムダ式
JavaScriptのfunctionに似てるが、レキシカルスコープ(変数の捕捉)のためにuseキーワードが必要
ひとつひとつの機能の話を語ったら20分では全然足りない
なので本日はPHPがどう変わっていったかというエピソードを交えてPHPの言語機能を紹介していきます
さて
PHP 7.4.0がリリースされましたね
12月1日は本日何の日でしょう?
この数は何でしょう
PHP7.4に向けて受理されたRFCの数
RFC?
(Request for Comment)RFC
新バージョンへの変更提案
PHPの機能の改廃の提案はRFCを通じて行われる提案はメーリングリストで議論されPHP.net VCSアカウントの所持者が議決する
の歴史PHP RFC
2008年頃から機能提案のために運用されはじめた
2011年(5.4alpha1)から正式なリリースプロセスになった
“PHP releases have always been done spontaneously, in a somehow chaotic way. Individual(s) decided when a release will happen and what could or could fit in. Release managers role are unclear and the way to nominate them is not clearly defined either.”‒ Request for Comments: Release Process https://wiki.php.net/rfc/releaseprocess
“PHPのリリースは常に無秩序な方法で自発的に行われてきました。個々人がいつリリースされるか、何が起こるか、そして何が収まるかを決定しています。リリースマネージャの役割は不明瞭で、指名の手続きも明確に定義されていません。”‒ Request for Comments: Release Process https://wiki.php.net/rfc/releaseprocess
(2008~2010年)この時期のPHPには何があったでしょう
この当時のPHP情勢
廣川さんの「PHPの今とこれから」が当時の事情の貴重な資料
‒ PHPの今とこれから2009 https://www.slideshare.net/hirokawa/php2009
‒ PHPの今とこれから2009 https://www.slideshare.net/hirokawa/php2009
‒ PHPの今とこれから2009 https://www.slideshare.net/hirokawa/php2009
Unicode化とはどういうことか?
言語処理系の文字列実装
CSI方式(Code Set Independent)
特定のコードセットに依存しない
UCS正規化方式(Universal Character Set)
内部的に文字コードを統一してから処理する
https://magazine.rubyist.net/articles/0025/0025-Ruby19_m17n.html
言語ごとの文字列実装
CSI方式
Ruby, Python 2, PHP
UCS正規化方式
Java, JavaScript, Perl,Python 3, PHP6
ざっくりCSI方式
文字列変換をしないので、オーバーヘッドは最小限
サポートする文字コードごとに文字列処理の実装が要る
ざっくりUCS正規化方式
文字列を変換するので入出力で変換オーバーヘッドがある
文字列処理は内部文字コード用のものだけ用意すればいい
PHP6はUTF-16を目指した
UCS正規化方式への移行
従来のPHP文字列はバイト列
PHP 5.2で(binary)キャストと b"string" が追加された
結局Unicode化しなかったので、ただのエイリアス
重要なこと
UCS正規化しないとUnicodeサポートできないわけではない
UTF-16にしても1コードポイント=1文字になるわけではない (サロゲートペア)
PHP6.0の顛末
実装は難航し、文字列以外の6.0向け機能は5.3, 5.4系でそれぞれリリースされた
2010年3月にリポジトリのtrunk(master)が5.3にロールバックした
開発が頓挫したPHP6は欠番としてスキップされPHP5.6の次は7.0になったというのは有名な話
(私はこの時代にPHPに触れておらず議論を詳しくは追ってないので想像の域は出ないが)
この時代にPHPはカウボーイによる開発スタイルを捨て、明文化されたスケジュールとプロセスによる開発体制に移行した
PHPのリリース計画やメンテナンス期間が定められたのもこのRFCから
PHP5.3ではPHP6を待たず重要な機能がマージされた
‒ PHPの今とこれから2009 https://www.slideshare.net/hirokawa/php2009
遅延静的束縛
static::method();
親クラスの静的メソッドから継承されたクラスのメソッドを呼び出す
ちなみにforward_static_call()関数のマニュアルには「静的メソッドをコールする」と書いてるが、この説明は間違い (翻訳の問題ではない)
Dynamic static call
Hoge::fuga()の代りに
$class="Hoge"; $class::fuga();
で呼べるようになった
静的メソッド版可変関数
名前空間
クラスや関数を階層化できる
名前空間違いの同名のクラスが作れるようになった
フルネームをFQSENと呼ぶ
useでファイルローカルな別名を付けることもできる
useの誤解されがちなところ
include/requireのようにファイルを読み込む機能ではない
ファイル内で呼べるようローカルな名前を付けるだけ
存在しないクラスをuseしてもエラーにはならない
クロージャ (関数式・ラムダ式)
ローカルな関数が作れる
ただの関数を作れるだけではなく、外側の変数を引き込めるのが重要 (関数閉包)
普通の関数やメソッドにその機能はない
クロージャ以前の無名関数
create_function()という関数で関数式っぽいことはできた
その実態はevalで lambda_1のような関数を動的に定義する
この関数はリスキーなのでPHP7.2からdeprecated
PHPのクロージャ
構文上はJavaScriptのものに似ているが、useで列挙しないと外側の変数を捕捉できない
この仕様にはPHPの変数の説明しにくい挙動が関わっている…
PHPの変数
PHPで変数の値を再代入したり引数に渡したりすると、(意味論として)値がコピーされる
クロージャでuseしたときもPHPでは引数と同じ動きになる
&を付けると変数の参照をとる
make_counter = function() {i = 0;return function () {return i++;};};
c1 = make_counter();
console.log(c1());console.log(c1());console.log(c1());
この記述だと$i=0のコピーされるだけ。 &を付けると変数リファレンスで値を更新できる
<?php$make_counter = function() {$i = 0;return function () use ($i) {return $i++;};};
$c1 = $make_counter();
var_dump($c1()); //=> 0 var_dump($c1()); //=> 0 var_dump($c1()); //=> 0
最初のRFCクロージャ
実はJavaScript風クロージャよりも前に短いクロージャが提案されてた (2008年3月)
RFC: Short syntax for anonymous functions
ただしDraft止まり
‒ PHP: rfc:short-syntax-for-anonymous-functions https://wiki.php.net/rfc/short-syntax-for-anonymous-functions
‒ PHP: rfc:short-syntax-for-anonymous-functions https://wiki.php.net/rfc/short-syntax-for-anonymous-functions
時は流れて2019年
PHP: rfc:arrow_functions_v2 https://wiki.php.net/rfc/arrow_functions_v2
PHP: rfc:arrow_functions_v2 https://wiki.php.net/rfc/arrow_functions_v2
姿形は違うが幾度もの議論の末に短い記法の関数式が導入された
ところで
PHP: rfc:arrow_functions_v2 https://wiki.php.net/rfc/arrow_functions_v2
私たちはこの提案者の名前を見たことがある!
‒ PHPの今とこれから2012 https://www.slideshare.net/hirokawa/php-now-and-then-2012-at-php-conference-2012-tokyo-japan
ジェネレータ
(古典的な)コルーチン
「何度も繰り返す」構造を関数(メソッド)を使って簡単に作れる
近年のPHPの中核的な開発者
PHP5.5以降、非常に多数の言語機能を実装してPHPに取り入れてきた
PHP-Parserなどの作者
去年の大学院を卒業し今年JetBrainsに入社してPhpStormチームに参加
とてもざっくり言うとレガシー仕様を消し、不条理な挙動は是正し、他言語にあるようなカッコイイ機能を追加提案してきた
不条理な挙動って?
例: 未定義定数はその文字列になる
echo PHP;
=> 文字列 "PHP" が出力
E_NOTICE/E_WARNING
error_reportingが低い環境でさりげなく生き残ってた可能性が高い
歴史的経緯で残ったレガシー仕様はさくっと消しまくっていこうぜ
いいじゃん
いいじゃん
📛
🔥
🔥
🔥
🔥
燃えた
Deprecate PHP's short open tags, again
一般的なPHPタグは<?php ... ?>または<?= ... ?> だが、<? ... ?>という形式もある
php.iniで有効無効を切替られる環境によってOnだったりOffだったり
Deprecate PHP's short open tags, again
XML宣言との相性がとても悪い
そんな半端モンは引導を渡してやろうぜ! ということで提案された
構文がシンプルになるし、機械的に変換もできるから良いだろ、という主旨
Zeevによる反論
PHP3・4の開発者
相方のAndi GutmansとともにVM型処理系のZend Engine開発
PHPでよくあるZend…はZeevとAndiに由来
PHPコードに未だに影響を残す
さらなる提案
続きはWebで
まとめ
PHPは力を手に入れようとして失敗してきた経験が結構ある
現在のPHPは静的解析できる環境が年々強まって往年のざっくりさは息をひそめつつある
銀河の平和はどっちだ
