CakePHP 5.3 で Table から Behavior のメソッドの呼び出しが deprecated になりました。
Since 5.3.0: Calling behavior methods on the table instance is deprecated.
Use `$table->getBehavior('YourBehavior')->slugify()` instead.
5.x では従来どおり動きますが 6.0 で削除予定です。
なぜ廃止されたか・移行(getBehavior('BehaviorName') または trait 利用)方法について調べてみたのでメモとして残します。
サマリ
- table に attach した behavior のメソッドを
$table->method()で直接呼ぶ(__callによるマジック委譲)が 5.3.0 で deprecated になりました。 - 移行は
$table->getBehavior('BehaviorName')->method()。またはBehaviorによる振る舞いを定義しているのではなく、単なるメソッド提供なら trait を利用する形へ。 - 5.3 でdeprecated、6.0 で削除予定
deprecationメッセージから見る移行
// Before(5.3 deprecated)
$slug = $articles->slugify($value);
// After
$slug = $articles->getBehavior('Sluggable')->slugify($value);
なぜ廃止されたか(RFC #18288)
提案者 ADmad が挙げた理由は次の通り:
-
trait があるので冗長。
$table->foo()で behavior メソッドを呼べる便利機能は、PHP に trait がある今は重複機能。単にメソッドを足したいだけなら trait で十分。 - プロキシのオーバーヘッド。table インスタンスで呼ぶたびに behavior へ委譲する余計なコード/チェックが走る。
- 静的解析を妨げる。ツールはこの「マジックメソッド」を認識できず、スタブや専用プラグインが無いと「method doesn't exist」になる。
-
リフレクション/重複メソッド問題。メソッド引数のリフレクションが壊れる。また
LocatorAwareTraitを 2 つの behavior で使い同一 table に load すると「duplicate method」で LogicException になる(behavior registry の重複チェック)。proxying をやめれば解消する。
移行の選択肢
getBehavior('Xxx')->method()(deprecation メッセージ・マイグレーションガイド通り)
getBehavior('BehaviorName') を通じて呼び出す。
$articles->getBehavior('Sluggable')->slug($value);
複数 table で共有している Behavior で定義した「振る舞い」は、Behavior のまま getBehavior() 経由で呼ぶ形が適切かと思います。
trait に移行
ライフサイクルや設定を持たない、ユーティリティメソッドなら trait 化して table で use する方がよい場合もありそうです。
参考記事:Behaviorを使うか、Traitにするか
(CakePHP 3.x 時代の記事ですが、判断基準として有用だと思います。)
- Trait 向き: メソッド提供のみ、カスタム finder
- Behavior 向き: ライフサイクルイベント購読、設定値管理、複数クラス共有
CakePHP RFC #18288 の趣旨(純粋なユーティリティは trait、振る舞いの共有は behavior 継続)とも一致します。
PHPStan 対応(@var が要る)
getBehavior('Xxx') の戻り型は基底 Cake\ORM\Behavior なので、そのままだと PHPStan は Call to an undefined method を出します。いまのところは、typed なローカル変数に受けて型を伝える必要があります。
/** @var \App\Model\Behavior\SluggableBehavior $sluggable */
$sluggable = $articles->getBehavior('Sluggable');
$slug = $sluggable->slug($value);
cakedc/cakephp-phpstan が getBehavior() の具象型解決に対応すれば、この @var は将来不要になる可能性がありそうです。(fetchTable() では既に具象 table 型を返すよう対応済みで、コア開発者も getBehavior() の同様対応に言及しています)。
まとめ
-
$table->method()→$table->getBehavior('Xxx')->method()(or trait 化)。 - PHPStan は
@varで behavior の型を明示。 - 6.0 で削除。5.x のうちに対応しておくことを推奨。
参考
- 5.3 Migration Guide — https://book.cakephp.org/5/en/appendices/5-3-migration-guide.html
- Behaviors(5.3.0 deprecation 明記・getBehavior 推奨)— https://book.cakephp.org/5/en/orm/behaviors.html
- RFC #18288 Drop the proxying of behavior methods through the table instance — https://github.com/cakephp/cakephp/issues/18288
- PR #18322 Deprecate calling of attached behavior methods on the table instance — https://github.com/cakephp/cakephp/pull/18322
- Behaviorを使うか、Traitにするか(cakephp-with-me, 2018)— https://cake.nichiyoubi.land/posts/32-behavior-vs-trait/