CakePHP 5.0 で Table の get() / find() で従来からの options 配列が deprecated になりました。
Since 5.0.0: Calling Table::get() with options array is deprecated. Use named arguments instead.
get($id, ['contain' => [...]]) のような options を配列で渡す従来の手法が deprecated になり、名前付き引数を使う形になっています。
置き換えは単純にできますが、get($id, contain: [...]) と名前付き引数で書くと VS Code の intelephense がエラーを出すという問題が生じるため、記録として残すことにしました。
サマリ
-
Table::get($id, array $options)の options を配列で渡す方法 5.0.0 で deprecated。 - 置き換えは 名前付き引数:
get($id, contain: [...])/get($id, finder: 'x', cache: 'y')。 -
find()も同様。 - ただし intelephense が
get($id, contain: ...)をUnknown named argument(P1044) とエラーになる。
変更点と deprecation 解消方法
Table::get() の options 指定が、options 配列から名前付き引数に変わりました。
// Before(CakePHP 5.0 deprecated)
$article = $articles->get($id, ['contain' => ['Comments'], 'finder' => 'published']);
// After(名前付き引数)
$article = $articles->get($id, contain: ['Comments'], finder: 'published');
// もしくは、上記は現在 VS Code intelephense のエラーが表示されてしまうので、下記の書き方も
$article = $articles->find()
->contain(['Comments'])
->where(['Articles.id' => $id])
->firstOrFail();
CakePHP 5.x ソースでのシグネチャ(抜粋):
public function get(
mixed $primaryKey,
array|string $finder = 'all',
CacheInterface|string|null $cache = null,
Closure|string|null $cacheKey = null,
mixed ...$args, // ← contain など finder/query オプションはここ
): EntityInterface
contain は ...$args(可変長)に名前付きで渡されることになります。
PHP 名前付き引数についての補足
名前付き引数(named arguments) は PHP 8.0 で導入された機能です。
関数(引数名: 値) つまり HogeFunction(optionA: 'value') のように引数を名前で指定して渡せます。
引数の順序に依存せず、途中の任意引数を飛ばして必要なものだけ渡すことができるようになりました。
なお、CakePHP 5 は PHP 8.1 以上が動作要件です。
options 配列をやめた理由
finder 引数刷新の CakePHP #12784「Support multiple arguments in finders」より抜粋、要約:
-
型安全でない。旧
find($type, array $options)/get($id, array $options)は、配列で渡されるため静的に型を検証できず、各オプションのキーの存在・型を自前コードで検証するしかなかった。 - PHP 8 の名前付き引数+型ヒントを使えば、引数の検証を言語レベルに任せられ、見通しが良くなる。
- 静的解析に優しくない。options 配列は「適切に注釈できないマジック」で、IDE や PHPStan がオプションのキー/型を理解できない。明示的な型付き/名前付き引数なら、ツールが型や構造を解析できる。
実装は可変長 ...$args +名前付き引数で行われました(PR #16782 / #17108)。
intelephense のエラー(P1044)
get($id, contain: [...]) と書くと、VS Code の intelephense が次のエラーを出します。
Unknown named argument $contain. intelephense(P1044)
これは誤検知とも言えるものです。contain は実シグネチャの可変長 ...$args に名前付き引数で渡されていますが、intelephense が「名前付き引数を可変長に渡す」PHP 8 の挙動を解釈できていないようです(intelephense #2524)。
PHPStan・実行時はエラーになりません。
対処(エディタへのエラー表示が気になる場合など、必要に応じて):
- そのまま放置しても問題はない(コード自体に問題はない。intelephense 側の修正を待ってもよいと思います)。
- インライン抑制: 問題行の直前に
/** @disregard P1044 */を入れる。 - ファイル単位で
settings.jsonのintelephense.diagnostics.excludeを入れる方法もあります。ただしパス単位で範囲が広くなってしまうので注意が必要。
別の方法として、下記の書き方(前述のやり方)でも同様の処理となり、intelephense でも問題は生じません(やや冗長かもしれませんが個人的にはこちらの方が好みです):
$article = $articles->find()
->contain(['Comments'])
->where(['Articles.id' => $id])
->firstOrFail();
参考
- 5.x
Table::get()(array|string $finder=「Passing an options array is deprecated」)— https://github.com/cakephp/cakephp/blob/5.x/src/ORM/Table.php - CakePHP #12784 Support multiple arguments in finders — https://github.com/cakephp/cakephp/issues/12784
- PR #16782 Allow typed finder arguments / PR #17108 5.x finder arguments no options — https://github.com/cakephp/cakephp/pull/16782 , https://github.com/cakephp/cakephp/pull/17108
- intelephense #2524(named 引数 × 可変長の誤検知)— https://github.com/bmewburn/vscode-intelephense/issues/2524