resourceは型宣言できない
resource型は型宣言できない。つまりfopen()した結果を引数で受け取ったり返すときは型を書けない。
https://3v4l.org/S7GRg
code:php
<?php
function read(resource $res): void {}
read(fopen('php://temp', 'rw'));
PHP 7
Fatal error: Uncaught TypeError: Argument 1 passed to read() must be an instance of resource, resource given
「resourceのインスタンスが必要なのにresourceを渡してるぞ」って怒られてる
型宣言ではresourceって型宣言してるんだが…?
PHP 8
Warning: "resource" is not a supported builtin type and will be interpreted as a class name. Write "\resource" to suppress this warning in /in/S7GRg on line 3
「resourceは型宣言がサポートしてる組み込み型じゃないし、クラス名として解釈すんぞ」って言ってる
説明通り\resourceって書いたからって型宣言できるわけじゃなくクラス名として扱われる
なぜresourceは型宣言できないのか
PHP 7.0で型宣言が追加された提案で明言されています。
PHP RFC: Scalar Type Declarations
Type declaration choices
No type declaration for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP).
かつてGMPがresourceからオブジェクトに移行したときと同じことをやるのでresource型に依存するなということ
ちなみにGMPがresourceだったのは5.5だけで、5.6で既にオブジェクト化している
resource型の肩身は年々狭くなっている
実際にPHP 8.0と8.1で結構移動された
PHP's resource to object transformation • PHP.Watch
8.0
https://gyazo.com/748981f95637232ce23bb518e5b9c757
8.1
https://gyazo.com/3d56da09683729f5c1af8f041b1bd13d
あまり直接は使われないものが多いが、そのなかでも使われる可能性があるのは以下あたりだろうか
PHP: curl_init - Manual
PHP: GD - Manual
一番使われるのがファイルハンドラのresouce
PHP: fopen - Manual
fopen()が影響範囲めちゃくちゃ大きそうだけど将来的にどうするんだろ
現実的にファイルを扱うにはどうすればいいか
PHPDocには書ける
code:php
<?php
/**
* @param resource|File
*/
function read($res): void {}
read(fopen('php://temp', 'rw'));
resourceを使わない
たとえばPSR-7: HTTP Message InterfacesのStreamInterfaceを使う
将来的のPHPでファイルハンドラが廃止された暁にはPSR-7自体のバージョンは上げなければいけなくが、自前で直接やらなくても各ライブラリでいい感じにしてくれるだろう
それが抽象化というものだ