コネヒト開発者ブログ

コネヒト開発者ブログ

CakePHP3.6.0のbeta1が出たのでおさらいしてみる

あけましておめでとうございます!からもう2ヵ月が経ちました。
最近はあまり新しい漫画を読んでいなかったのですが、ザ・ファブルに手を出し始めました!

ザ・ファブル

ザ・ファブル

サーバー側開発をやっております金城 (o0h_)です。

弊社ではWebApplicationは主にCakePHPを用いて開発を行っていますが、次期バージョンである3.6のベータ版がリリースされました。(おめでとうございます!🎉)

bakery.cakephp.org

そんなCakePHP 3.6.0-beta1について、予習をかねて覗いて見たいと思います。

CakePHP4と3.6

今回リリースされる3.6ですが、実は思いっきり4.xを見据えたバージョンとして位置づけられているものです。

昨夏、CakePHP4へのロードマップについての発表がありました。
当時の内容を以下の記事に書いております。

tech.connehito.com

この記事中でも言及していますが、Bakery*1Upcoming CakePHP Roadmap & Releases のエントリーを見ると、

  • If your application runs in the latest 3.6 without any deprecation errors, then it should run in 4.0.0 with minimal effort
  • In an ideal world, we’d like to release 3.6 and 4.0 very close to each other.
  • This would make 3.6 the last 3.x with the possibility of 3.7 happening.

というように言及がなされています。
そのため、「機能的に大きな変更はないが、コミュニティにとっては非常に意義深いものである」のではないかと個人的には考えています。

CakePHPコミュニティとメジャーバージョンアップ

引き続きの引用となりますが、 Unlike the upgrade from 2.x to 3.x we want this to be a dramatically simpler upgrade. と述べられているのには強い意志を感じます。
「真っ当に3.6を使っていれば、4.xは使ってもらえるようになる」と*2
少し蛇足となりますが、先日こんな興味深い議論が行われています。

github.com

こちらは、「まだ_ prefixメソッドやメンバがあるが、4.0では避けるべきでは」という問題提起です。
CakePHPでは、PSR-2に従う形でvisibilityを表現するためにアンダースコアを接頭するのをやめています。*3

ref)

しかしながら、内部的にはまだ「取り除ききれていない」のも事実です。
例えば、(ちょっと事情が異なるかもしれないですが)Entityは以下のようなアクセサを用意しています。
ここで $_properties が登場するのです

// https://github.com/cakephp/cakephp/blob/master/src/Datasource/EntityTrait.php#L279-L299
<?php
    public function &get($property)
    {
        if (!strlen((string)$property)) {
            throw new InvalidArgumentException('Cannot get an empty property');
        }
        $value = null;
        $method = static::_accessor($property, 'get');
        if (isset($this->_properties[$property])) {
            $value =& $this->_properties[$property];
        }
        if ($method) {
            $result = $this->{$method}($value);
            return $result;
        }
        return $value;
    }

このIssueも「あるべき姿」を考えれば実現されるべきでしょう。つまり、↑の例で言えば $properties となっていて然るべきです。
しかしながら、「これは4.0に取り込まれるべきではない」として決着しています。
なぜでしょうか?正に、今のコミュニティとしてのCakePHPの考え方を表している意思決定だったように個人的に感じました。
このコメントに良く凝縮されているので、丸っと引用してみます。

I think the point is that we have learned our lesson from the big breaking changes between 2.x and 3.x. The lesson is that the many very large in the wild cake applications remain in 2.x because of the difficulty in upgrading. We are trying to prevent that issue in future major versions to help promote upgrading, while trying to strike the balance with BC and new features/practices.

なかなかのツラミがありますね・・・自分はフレームワークとしてのCakePHPが好きだし手に馴染むと思っていますが、そんな立場からでも「2.x系から3.x系への移行を考える」というのは非常に難儀に思われました。
これがコミュニティにとっての「教訓」だったとして、「もし必要な変更でも、ユーザーに対して乱暴であれば見送る」というのが、今の判断なのだなぁと感じます。それが「メジャーバージョンアップだったとしても」です。*4

「4.x」手前のバージョンとしての3.6

そんな今、「次のバージョンへの橋渡し」としての重要な位置付けとしての3.6にはどんな変更が盛り込まれているのでしょうか?
それを知るには、移行ガイドとロードマップを見るのが良いでしょう。

Deprecatedになったもの

migration guideを見ています。

  • 例によってDeprecationsを見ると(3.4から続く)「mutator/accessorの分離・提供」の変更が多いのですが、Cake\ORM\TableRegistry static API has been deprecated という変更が入りました。背景については こちらを御覧ください。
  • Cake\Network の中身が Cake\Http にたくさん移動しています。
    • Cake\Networkに関する変更は、 3.3の流れをくむものでしょうか。

Deprecatedメソッドの利用時にwarningを発するように

wikiを見ています。
個人的には、今回の変更ではこれが最も大きいかつ特徴的な部分かな?と思っているのですが、 In order to ease the migration into 4.x, all current deprecations that exist only as documentation warnings will be upgraded to run-time E_USER_DEPRECATED errors ということです。
実装についてはこのPRや、この関数を利用している各後続実装を確認してください。
3.6 - Add a deprecation warning helper. by markstory · Pull Request #11075 · cakephp/cakephp · GitHub

メジャーバージョンアップでは「アップデートしたら動かなかった」が1番怖いことだと思いますが、その前に「互換性のあるアップデートを行ったあとに、warningを全部潰しておけば次期バージョンでの最低限の動作を保証する」というのは非常に親切だなぁと感じました。これは既存の3.x系ユーザに対して3.6の利用を促すインセンティブにもなりそうだし、「頑張って今できることをやっていけば、すぐ次を使えるよ!」というのは個人的にはテンションも上がる気がしました 。

RoutingのDSL変更(追加)

Entity Routing

RFC : EntityRouting · Issue #11277 · cakephp/cakephp · GitHubという機能が追加されます。
bookによれば、

$routes->get(
    '/view/:id',
    ['controller' => 'Articles', 'action' => 'view'],
    'articles:view'
);

という記述が

use Cake\Routing\Route\EntityRoute;

// Create entity routes for the rest of this scope.
$routes->setRouteClass(EntityRoute::class);
Router::url(['_name' => 'articles:view', '_entity' => $article]);

という記述でOK!となるようで、特にリソース中心な設計を行っているアプリケーションでは従来より簡潔に開発が進められるようになるかもしれません。

controller::action 形式のRouting

Implementing reverse routing syntax by burzum · Pull Request #11688 · cakephp/cakephp · GitHub

コントローラーとアクションを指定するルーティングが、簡潔に記述可能になっています。

$routes->connect('/my-articles/view', 'Articles::view');

Plugin Objects

プラグイン周りに入った変更も、結構な「大改造」と言える気がします。

Implement Plugin Classes by burzum · Pull Request #11564 · cakephp/cakephp · GitHub

この登場で、プラグインが自身で行えるライフサイクルへの干渉・注入の柔軟性が高まったように思います。
Plugins - 3.nextにて、利用イメージに触れられていますが、しっかり読もうとすると少し大変そうなので、また改めて確認してみたいと思います。

最後に

個別の機能を眺めていて、3.6はやはり「4.xへのジャンプのためのしゃがみ込み」とでもいうような印象を受けました。
プラグインやルーティング、ここでは触れていませんがMiddleware周りで大きな変更や強力な機能導入も行いつつも、「3系としての実質最終バージョンとして」の姿があるように思います。

もちろん、まだBeta-1ということでここからNew Featuresは入ってくると思いますが、機を見て実際に触れていきたい気持ちです!

それでは、よい年度末を〜

*1:CakePHPのオフィシャルブログ

*2:ただし、PHPの要求バージョンが上がっている点などは要注意です!

*3:Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility. https://www.php-fig.org/psr/psr-2/

*4:背景的には、PHP5.3/5.4の登場やcomposerの普及といった大きな潮流の変化があったことで、「それ以前」のコードが一気に古臭くなりやすい!といった要因も看過はできません。この激流の中にあっては、ちょうどCakePHP3.0が出るときには「未来のための切り捨て」も已むを得ない部分が大きかったのではないでしょうか。