来たるCakePHP 4.0 を知ろう

[CakePHP Advent Calendar 2019](https://qiita.com/advent-calendar/2019/cakephp)の1日目がやってきました。今年のCakePHPの大きなトピックとしては、[CakeFest](https://cakefest.org/)が日本で開催されたことではなかったでしょうか。CakeFest 2019では、CakePHPのFounderである[Larry Masters](https://www.cakedc.com/team/phpnut)さんや、Lead Developerである[Mark Story][markstory]さんなど、CakePHPのコアメンバーの方々が一同した会でした。そこで、CakeFest 2017に続き、CakePHPの次のメジャーバージョン **4.0** の説明がありました。初日の本日は、そんなCakePHP 4.0をざっくり知る記事を展開していきます。

[markstory]: https://twitter.com/mark_story

# CakePHP 4.0 のこれまでの経緯

CakeFest 2017で行われた[Mark Story][markstory]のプレゼンテーション「[CakePHP - The Road Ahead](https://www.slideshare.net/markstory/cakephp-the-road-ahead)」にて、CakePHPの過去と現在と未来の話をされていました。

https://www.slideshare.net/markstory/cakephp-the-road-ahead

その中で、未来のCakePHPの話としてメジャーバージョン 4.0 のアイデアの紹介がされました。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Announcing CakePHP 4 Strawberry. To be built upon the shoulders of giants! <a href="https://twitter.com/hashtag/CakePHP?src=hash&amp;ref_src=twsrc%5Etfw">#CakePHP</a> <a href="https://twitter.com/hashtag/announcement?src=hash&amp;ref_src=twsrc%5Etfw">#announcement</a> <a href="https://t.co/ExpEP118d1">https://t.co/ExpEP118d1</a></p>&mdash; CakePHP (@cakephp) <a href="https://twitter.com/cakephp/status/877888565442560000?ref_src=twsrc%5Etfw">June 22, 2017</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

その直後2017年6月23日に、「[Upcoming CakePHP Roadmap & Releases](https://bakery.cakephp.org/2017/06/23/upcoming-cakephp-roadmap.html)」が公開され、CakePHP 4  のアナウンスがされました。

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Work on CakePHP 4 has started! What would you like to see in future releases? Check out the CakePHP 4 roadmap <a href="https://twitter.com/hashtag/CakePHP?src=hash&amp;ref_src=twsrc%5Etfw">#CakePHP</a> <a href="https://twitter.com/hashtag/oss?src=hash&amp;ref_src=twsrc%5Etfw">#oss</a> <a href="https://twitter.com/hashtag/php?src=hash&amp;ref_src=twsrc%5Etfw">#php</a> <a href="https://twitter.com/hashtag/phpc?src=hash&amp;ref_src=twsrc%5Etfw">#phpc</a> <a href="https://twitter.com/hashtag/opensource?src=hash&amp;ref_src=twsrc%5Etfw">#opensource</a> <a href="https://twitter.com/hashtag/CakePHP4?src=hash&amp;ref_src=twsrc%5Etfw">#CakePHP4</a> <a href="https://t.co/XwumvUd4um">https://t.co/XwumvUd4um</a> <a href="https://t.co/XKHXyubO1p">pic.twitter.com/XKHXyubO1p</a></p>&mdash; CakePHP (@cakephp) <a href="https://twitter.com/cakephp/status/1003609827631947777?ref_src=twsrc%5Etfw">June 4, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そして、2018年6月4日に、CakePHP 4 の開発開始が告知され、4.0のRoadmapが紹介されました。

https://github.com/cakephp/cakephp/wiki/4.0-Roadmap

CakePHP 4.0 の開発進捗は、その後コアデベロッパーのツイッターにて時々見受けられるようになり、例えば2019年1月29日には、CakePHP 4.0 が[PSR-15][psr15]のサポートをする実装ができたといったツイートがされるなど、進んでいっていました。

[psr15]: https://www.php-fig.org/psr/psr-15/

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">CakePHP 4.0 will support PSR15 🎉 <a href="https://t.co/1iKEBwRt6Y">https://t.co/1iKEBwRt6Y</a></p>&mdash; Mark Story (@mark_story) <a href="https://twitter.com/mark_story/status/1090084761433968640?ref_src=twsrc%5Etfw">January 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

開発が進んでいく中で、2019年11月7日（木）〜11月10日（日）に開催された、CakeFest 2019にて、「[Safer, More Helpful CakePHP](https://www.slideshare.net/markstory/safer-more-helpful-cakephp)」という発表が[Mark Story][markstory]さんにて行われて、具体的なCakePHP 4.0 についての説明があり、「もうすぐリリースか！」といった温度感を感じる内容となっていました。

https://www.slideshare.net/markstory/safer-more-helpful-cakephp

# CakePHP 4.0 の特徴

[Safer, More Helpful CakePHP](https://www.slideshare.net/markstory/safer-more-helpful-cakephp)の発表内で、CakePHP 4.0 を説明する一文として、

**EARLY FEEDBACK & SAFETY**

という言葉を使っています。4.0 についての新機能や新たな非推奨は、[4.0 Migration Guide](https://book.cakephp.org/4/en/appendices/4-0-migration-guide.html
)にて確認することができます。

https://book.cakephp.org/4/en/appendices/4-0-migration-guide.html

大まかな部分として、次のような特徴を持っています。

## PHP7.2+

4.0 では、PHP 7.2以上をrequirementとしています。7.2以上とすることで、PHPにおける型機能がCakePHPの内部実装においても使えるようになっています。これは、GitHubのIssue、[Raise minimum version of PHP to 7.2 for 4.0](https://github.com/cakephp/cakephp/issues/13103)での投票にて決定しました。

https://github.com/cakephp/cakephp/issues/13103

そのため、CakePHPの 4.x ブランチにおける composer.json でも php 7.2.0以上を requireとして定義されています。

```json
    "require": {
        "php": ">=7.2.0",
```

https://github.com/cakephp/cakephp/blob/a0262efd1cc077842250e705f8cceadafda109de/composer.json#L31

## STRICTER TYPING

4.0 では、内部実装において基本的にすべてのPHPファイルで、`declare(strict_types=1);`を定義し、厳密な型チェックを有効にしています。

https://www.php.net/manual/ja/functions.arguments.php#functions.arguments.type-declaration.strict

試しに、Routeクラスをピックアップすると、次のように定義されていることがわかります。

```
<?php
declare(strict_types=1);
```

https://github.com/cakephp/cakephp/blob/7a4c880bd63ce886dc75cc23f536781a16591f47/src/Routing/Route/Route.php#L2

## 戻り値型宣言

PHP7.2以上としたことによって、スカラー型宣言を利用できるので、内部実装において、戻り値の型宣言を多く使用しています。また、`array|bool`といったエラーハンドリングがされていたような実装は、nullable型を利用し型宣言をできるようしています。

例えば、Routeクラスのparse()というメソッドを見てみると、3.xの場合は、

```php
    public function parse($url, $method = '')
    {
        if (empty($this->_compiledRoute)) {
            $this->compile();
        }
        list($url, $ext) = $this->_parseExtension($url);

        if (!preg_match($this->_compiledRoute, urldecode($url), $route)) {
            return false;
        }
```

https://github.com/cakephp/cakephp/blob/0b1361564a8a497aa287fa8acc0357ef3f13197e/src/Routing/Route/Route.php#L426

と失敗した場合は`false`を返すような実装は、4.xにて次のようになりました。

```php
    public function parse(string $url, string $method): ?array
    {
        $compiledRoute = $this->compile();
        [$url, $ext] = $this->_parseExtension($url);

        if (!preg_match($compiledRoute, urldecode($url), $route)) {
            return null;
        }
```

https://github.com/cakephp/cakephp/blob/7a4c880bd63ce886dc75cc23f536781a16591f47/src/Routing/Route/Route.php#L422

## PSR-15,16対応

すでに3.xでマージされているものもありますが、[4.0 Roadmap](https://github.com/cakephp/cakephp/wiki/4.0-Roadmap)にて、PSR-15やPSR-16対応がされていきました。

[PSR](https://www.php-fig.org/psr/)とは、PHP Standards Recommendationsであり、各種物議を醸しつつも、コミュニティにて影響が大きい勧告です。

https://www.php-fig.org/psr/

PSR-15は、Middlewareに関連するものですが、4.xに向けて対応がされマージされています。

https://github.com/cakephp/cakephp/pull/12907

PSR16はCacheに関するものですが、こちらも3.7の段階で対応が完了しています。

https://github.com/cakephp/cakephp/pull/12907

これらに関する説明について、2019年1月に自分がPHP勉強会で発表した「[Steadily developing CakePHP 4.0](https://speakerdeck.com/hgsgtk/steadily-developing-cakephp-4-dot-0-number-phpstudy?slide=30)」にて説明しているので、気になる方はこちらをご覧ください。

<script async class="speakerdeck-embed" data-slide="30" data-id="9340a3eb7ba44ec19a0e0977ae155934" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>

# 使用者として気がついたこと

これまで、CakePHPの内部にてどういうふうに変わったかという話をしていましたが、実際に使用者側としてどういうことを感じたかという点を、主観でピックアップしていきます。

## templatesについて

templatesについてまずディレクトリ構成が変わり、`src`以下から飛び出し、別途`templates`ディレクトリができました。

```
src/
templates/
```

https://github.com/cakephp/cakephp/tree/45becd398ac060c9d1f379c42627a6ba81158933/templates

これは、CakeFest 2019にて、日本人コアコミッターである[@chinpei215](https://twitter.com/chinpei215)さんが解説されていましたが、セキュリティホールに対する対応とのことでした。

https://github.com/cakephp/cakephp/issues/11760#issuecomment-368437105

> As I said in the dev channel, this change could be a security hole accidentally. If you call class_exists('App\Template\Users\index'), composer will include index.php. If we want to do that, we would also have to move the Template directory to the root directory like config or bin.

また、このissueのタイトル「[RFC: Use .php extension by default for templates.](https://github.com/cakephp/cakephp/issues/11760)」にもありますが、テンプレートファイルのデフォルトの拡張子が`.ctp`から`.php`に変更されました。

## JSON viewを返却する際の変更

4.0 において、`JsonView`の特殊なビュー変数である`_serialize`や`_jsonOptions`、`_jsonp`が非推奨となりました。そのため、JSONを返すAPIを作る場合に次のようなコードを書くことになったようです。

```php
    public function view($slug = null)
    {
        $article = $this->Articles->findBySlug($slug)->firstOrFail();
        $this->viewBuilder()
            ->setClassName(JsonView::class)
            ->setOption('serialize', 'response');
        $this->set('response', ['article' => $article]);
    }
```

# 4.0 へのアップデート

既存システムの4.0へのバージョンアップは、CakePHP3.8へアップグレードし、PHP7.2以上にバージョンアップしてから4.0にあげるのがベターなようです。

それにあたって、様々非推奨になったAPIが存在するので、非推奨機能の利用をすべて排除してから上げる必要があります。

実際、昨今の3.xのマイグレーションガイドでは、Deprecationsの告知が非常に多くなっています。

- [3.6 Migration Guide](https://book.cakephp.org/3/en/appendices/3-6-migration-guide.html)
- [3.7 Migration Guide](https://book.cakephp.org/3/en/appendices/3-7-migration-guide.html)
- [3.8 Migration Guide](https://book.cakephp.org/3/en/appendices/3-8-migration-guide.html)

逆に言うと、非推奨機能の利用を取り除けば、3.xから4.0にバージョンアップできるということになります。

また、アップデートツールも用意されています。

https://github.com/cakephp/upgrade/tree/4.x

# 現在サポート中のバージョン

2.xや3.xのバージョンのサポートに関しては次のスケジュールとなっています。

## 2.x

- Bug fixes for 12 months after the release of 4.0.0
- Security fixes for 18 months after the release of 4.0.0

## 3.x

- Security fixes for 36 months after 4.0.0 is released

# 最後に
2日目の[CakePHP Advent Calendar 2019](https://qiita.com/advent-calendar/2019/cakephp)は、@nojimageさんの記事です。楽しみですね！ではまた！