ここ最近提出されたPHP RFCをなんとなく新しい順に見てみました。
これらは将来のPHPに確実に実装されるというわけではなく、却下されることも十分にありえます。
というか見た感じ半分以上却下されるんじゃないかしら。
RFC
日付はRFCのDateに書かれてるものですが、これが提出日なのか更新日なのか何かの記念日なのかわからない。
そもそもRFCの並び順が新しい順とかじゃなくて適当なんだけどなにこれ。
Immutable classes and properties
2018/02/19提出。
新たなキーワードimmutableをくれ、という提案。
immutable class Foo {
public $email;
public function __construct($email) {
$this->email = $email;
}
}
// コンストラクタ以外では変更不可
$email = new Foo("foo@example.com"); // OK
$email->email = "bar@example.com" // Fatal Error
// extendsも不可
class Bar extends Foo{} // Fatal Error
immutableなクラスは、インスタンス作成時のコンストラクタ以外での内部プロパティ変更が不可能になります。
プロパティにもimmutableを指定できます。
class A {
public immutable $x;
public $y;
public function __construct($x, $y = null){
$this->x = $x;
$this->y = $y;
}
}
// $xはコンストラクタ以外では変更不可
$a = new A(1, 2);
$a->x = 3; // Fatal Error
$a->y = 4; // こちらはOK
// immutableでない型は渡せない
new A('text'); // OK
new A(new Foo()); // むしろimmutableなクラスはimmutableプロパティでないと駄目
new A([]); // Fatal Error 配列はNG
new A(fopen('hoge.txt', 'r')); // Fatal Error リソースも不可
niigataアクセス修飾子!niigataアクセス修飾子じゃないか!
しかしリソースはまだしも配列が駄目というあたりがやな感じである。
それ以前にそもそもPHPにimmutableなんて必要なのかね、と思わないでもないんだけど、そういえばDateTimeImmutableがないと生きていけないんだった。
Deprecate backtick operator
2018/02/11提出。
バッククォート`をDeprecatedにしようという提案。
バッククォートはshell_execと等価で、いきなりソースに書かれてたりするとわかりにくいことこの上ないので、個人的には正直要らないと思うのですが、フォーラムを見るかぎり否定派が多そうです。
先に削除するのは@
だろう、とか。
というか提案者の話し方がちょっと微妙というか説得させる気がとても感じられない。
おそらく却下されるんじゃないかな。
Argon2 Password Hash Enhancements
2018/01/11提出。
Argon2idの実装提案。
PHP5.5でpassword_hashという超絶便利関数が実装されました。
PHP7.2現在では、この関数で使用できるハッシュアルゴリズムはPASSWORD_BCRYPTとPASSWORD_ARGON2Iの2種類だけです。
Argon2は環境に応じて暗号強度を変えられるというハッシュアルゴリズムで、現在3種類のバージョンが存在します。
Argon2dはGPUクラッキング耐性を重視したアルゴリズムで、Argon2iはタイミング攻撃などのサイドチャネル攻撃に強くなるようデザインされたアルゴリズムです。
弱点はそれぞれ反対で、Argon2dはサイドチャネル攻撃に弱く、Argon2iはGPUクラッキング攻撃に弱くなります。
PHPに実装されているのはArgon2iです。
両者のいいとこ取りをした第三のアルゴリズムArgon2idというものがあるので、次バージョンでそのハッシュアルゴリズムPASSWORD_ARGON2IDを追加しようという提案です。
そんな便利なアルゴリズムがあるなら何故最初から導入しなかったのかというと、当時はまだArgon2idの仕様が固まってなかったからのようです。
別記事でも書いたように、password_*関数はアルゴリズムの変更がきわめて容易なので、さくっと対応してもらえるといいですね。
Scalar Pseudo-type
2017/12/24提出。
スカラー疑似型がほしい、という提案。
is_scalarという関数は昔からあるものの、対応する型は実は今まで存在しませんでした。
そこで対応する疑似型を作りましょう。
// scalar疑似型
function f1(scalar $param) :scalar{
return $param;
}
f1(1); // OK
f1(null); // NG
// scalar疑似型のイメージ
function f2(bool | float | int | string $param) :bool | float | int | string {
return $param;
}
// NULL許容scalar疑似型
function f3(?scalar $param) {
echo "{$param}\n";
}
f3(null); // OK
f3(); // NG
いやあ、そもそも引数をもっと厳格にしろ、と言いたい。
bool | float | int | stringが返ってくる関数とか半端すぎて使い道に困るだろ。
Explicit call-site pass-by-reference
2017/12/02提出。
参照渡し関数は呼び出し側に&
を付けられるようにしよう、という提案。
function inc(&$num) { $num++; }
$i = 0;
inc(&$i);
var_dump($i); // int(1)
見える、PHP4時代の老兵が錯乱する様が見えるぞ。
しかし、これはかつての『呼び出し側に&を付けるだけで参照渡しになる』機能とは異なります。
関数が既に参照渡しである場合にかぎり&を付けてもエラーにならないようにする、というだけの内容です。
// 普通の関数は呼び出しに&を付けられない
function inc2($num) { return $num+1; }
inc(&$i); // Cannot pass reference to by-value parameter 1
参照渡し問題に対する根本的かつ唯一の解は、参照渡しを一切使用しないことです。
PHPに参照渡しなど不要。
と言いたいところなのですが、実はそうもいかない問題があるのです。
そもそも何故このような提案が出てきたかというと、たとえば以下です。
$ret = array_slice($array, 0, 3);
$ret = array_splice($array, 0, 3);
これを見て$array
がどうなるかわかる人は変態だけです。
$ret = array_slice($array, 0, 3);
$ret = array_splice(&$array, 0, 3);
こう書けば、どうなるか多少わかりやすくなります。
なお、この記述はあくまでオプションで、これまでのように付けなくても動作します。
機能的にはよい内容だと思うのですが、問題はこれが書かれたソースを見たときにうっかり「こんな古生代の書き方した奴は誰だ!」とか思ってしまいそうなところでしょうか。
Fiber
2017/09/13提出。
軽量な実行スレッドFiberを導入しようという提案。
function sub1(){
return Fiber::yield(1);
}
$fiber = new Fiber(function ($a, $b) {
$c = Fiber::yield($a + $b);
$d = sub1();
return $d.$c;
});
echo $fiber->resume(1, 2); // echo 3
echo $fiber->resume("world"); // echo 1
echo $fiber->resume("hello "); // echo "hello world"
yield
で処理を中断し、resume
でその続きから実行する、ということでRubyのFiberやLuaのコルーチンと同じものです。
しかしGeneratorとどう違うのか正直よくわからない。
別関数をyield from
って呼ばなくてよくなったくらい?
Operator functions
2017/09/08提出。
関数を渡す関数に演算子を渡したいという要望。
// 配列を全部足す
$arr = [1, 3, 5];
$sum = array_reduce($arr, function($a, $b){return $a+$b;});
// こう書ける
$sum = array_reduce($arr, '+');
この場合はarray_sum
でいいんだけど、そういう特殊な関数ではなく汎用的なところで便利になる場合が…
usort($data, '<=>'); // sort() と同じ
'**'(5, 8); // 5**8 と同じ
'||'($a, $b); // $a || $b と同じ
要るかこの機能?
'||'($a, $b, $c, $d)
とか書けるならもしかしたらワンチャン?
演算子を関数として扱えるようになるということなので、今後はユーザ定義演算子を追加するようなことも考えているようです。
もしかしたらrunkit_operator_redefine()
みたいなものも現れるかもしれませんね。
是非辞めていただきたい。
Mixed typehint
2017/07/19提出。
疑似型mixedがほしい、という提案。
function foo(mixed $arg): mixed {
return $arg;
}
これならまだscalarn疑似型のほうがマシだよ。
こんなもん却下だ却下。
Deprecate PDO::PARAM_NULL
2017/05/15提出。
PDO::PARAM_NULLっていらなくね?
// 現在
$statement->bindValue(1, null, PDO::PARAM_NULL);
// 変更後
$statement->bindValue(1, null);
そもそもSQL標準には、nullを許容する型はあれど、null型という型はないので、NULLデータ型という定義自体がおかしいです。
さらに現状のPDOドライバは引数がnullだったらPDO::PARAM_*を気にせず値がnullになるので、実用上も問題ありません。
ということで削除しましょう。
Deprecation of fallback to root scope
2017/03/05提出。
グローバル空間へのフォールバックをやめよう。
namespace Bar;
strlen();
このstrlenはまず\Bar\strlen()
を探し、それが存在しなければ\strlen()
を見に行きます。
この機能のおかげでPHPの標準関数は全てグローバルに使用することができるわけです。
実はこの機能のせいで、途中で関数定義が変わってしまう場合があります。
namespace foo{
$t = 'テキスト';
echo strlen($t);
echo strlen($t);
if(true){ function strlen($t){return mb_strlen($t);} }
echo strlen($t);
echo strlen($t);
}
上2つのstrlenは\strlen()
を、下2つのstrlenは\foo\strlen()
を呼び出します。
意図せずrunkit_function_redefineのようなことが起こってしまいました。
といっていきなりフォールバックを禁止すると死者が続出するので、このRFCではE_NOTICEを出すだけにしておいて、次のバージョンで削除する予定のようです。
しかし、この提案はさすがにちょっと影響範囲が大きすぎるので、そう簡単には受け入れられないんじゃないかなと思います。
フォーラムでは「こんなん実装したらみんなエラーメッセージの海に埋もれて死ぬわ」とか言われてます。
Arrow Functions
2016/08/14提出。
これは少し古いけど興味深かったので。
// $x*2を返す関数
$mul2 = fn($x) => $x * 2;
$mul2(3); // 6
なんかすごい何処かで見たことのあるような構文だな。
// $versionAと$versionBは同じ
$y = 1;
$versionA = fn($x) => $x + $y; // $yが見える
$versionB = function ($x) use ($y) {
return $x + $y;
};
// $extended1と$extended2は同じ
$extended1 = function ($c) use ($callable, $factory) {
return $callable($factory($c), $c);
};
$extended2 = fn($c) => $callable($factory($c), $c); // $callableや$factoryが見える
文法そのものは悪くないんじゃないかと思いますが、スコープを無視して変数が見えるのはとても気持ち悪いです。
実はこれ元ネタから存在している仕様なのですが、だからといってわざわざ汚点まで持ってくる必要はないでしょう。
var f = (x) => { return x + y; };
f(1); // Uncaught ReferenceError: y is not defined
y=5;
f(1); // 6
感想
ジェネレータや可変長引数、戻り値型宣言のような心躍る新機能がいまいち見当たらない。
Arrow Functionsは面白そうだけど、採用されそうな気が全くしないのは何故だろう。
ところでいつも思うんだけど、無名関数ってどうせconstとかに突っ込むんだから結局名前あるよね(関係ない)