20211201のPHPに関する記事は12件です。

laravel8 Storageファサードのドライバの振る舞い

目的 Storage::get()の振る舞いについて若干詰まったので簡単にまとめておく Storageファサードの振る舞い そもそもStorageファサードはdisc()メソッドや.envで指定しない限りconfig/filesystems.phpの'default'で指定されたドライバを参照しにいく。 ここで言うドライバとはローカルとかS3とかの記憶する「場所」の話である。 完全にデフォルトの場合下記のように記載されてlaravelプロダクトのローカルを参照するようになっている。 config/filesystems.php /* |-------------------------------------------------------------------------- | Default Filesystem Disk |-------------------------------------------------------------------------- | | Here you may specify the default filesystem disk that should be used | by the framework. The "local" disk, as well as a variety of cloud | based disks are available to your application. Just store away! | */ 'default' => env('FILESYSTEM_DRIVER', 'local'), 下記の様に.envに記載されている 場合、ドライバはs3が指定されている。 FILESYSTEM_DRIVER=s3 この場合Storageファサードを使った処理はdisk()メソッドで指定しない限りs3を参照して実行される。 なので「殆どのファイルはs3に上げたいけど、ローカルでzipファイルに固めてダウンロードしたい」などのケースでzipをダウンロードする場合下記のように記載する。 Storage::download()を用いる場合(あくまでダウンロード処理の例のみ記載、コチラだけを記載してもzipで固めてダウンロードしてくれない) Storage::disk('local')->download('ファイルパス', 'ファイル名', 'ヘッダー'); response()を用いる場合 response()->download('ファイルパス', 'ファイル名', 'ヘッダー'); // ダウンロード後のファイルを削除してほしい場合、deleteFileAfterSend(true)を呼ぶ response()->download('ファイルパス', 'ファイル名', 'ヘッダー')->deleteFileAfterSend(true); 参考文献 https://readouble.com/laravel/5.8/ja/filesystem.html#storage ディスクインスタンス取得部分 https://stackoverflow.com/questions/44769693/laravel-file-not-found-at-path-but-it-does-exist
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel Storageファサードのドライバの振る舞い

目的 Storage::get()の振る舞いについて若干詰まったので簡単にまとめておく Storageファサードの振る舞い そもそもStorageファサードはdisc()メソッドや.envで指定しない限りconfig/filesystems.phpの'default'で指定されたドライバを参照しにいく。 ここで言うドライバとはローカルとかS3とかの記憶する「場所」の話である。 完全にデフォルトの場合下記のように記載されてlaravelプロダクトのローカルを参照するようになっている。 config/filesystems.php /* |-------------------------------------------------------------------------- | Default Filesystem Disk |-------------------------------------------------------------------------- | | Here you may specify the default filesystem disk that should be used | by the framework. The "local" disk, as well as a variety of cloud | based disks are available to your application. Just store away! | */ 'default' => env('FILESYSTEM_DRIVER', 'local'), 下記の様に.envに記載されている 場合、ドライバはs3が指定されている。 FILESYSTEM_DRIVER=s3 この場合Storageファサードを使った処理はdisk()メソッドで指定しない限りs3を参照して実行される。 なので「殆どのファイルはs3に上げたいけど、ローカルでzipファイルに固めてダウンロードしたい」などのケースでzipをダウンロードする場合下記のように記載する。 Storage::download()を用いる場合(あくまでダウンロード処理の例のみ記載、コチラだけを記載してもzipで固めてダウンロードしてくれない) Storage::disk('local')->download('ファイルパス', 'ファイル名', 'ヘッダー'); response()を用いる場合 response()->download('ファイルパス', 'ファイル名', 'ヘッダー'); // ダウンロード後のファイルを削除してほしい場合、deleteFileAfterSend(true)を呼ぶ response()->download('ファイルパス', 'ファイル名', 'ヘッダー')->deleteFileAfterSend(true); 参考文献 https://readouble.com/laravel/5.8/ja/filesystem.html#storage ディスクインスタンス取得部分
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初学者が「変数って何なの???」を乗り越えた話

この記事は、2021年4月にプログラミングを始めたわたしが 最初にぶつかった壁である「変数って何なの???」をなんとか乗り越えたよ〜という内容です。 初学者の方で、当時のわたしと同じように悩んでおられる方のお役に立てましたら嬉しいです。 ・ ・ ・ ■ 最初の壁 プログラミングって何か楽しそう〜と思い、 「プログラミング言語ってこんなにいっぱいあるんだー」とか「フレームワークって何w」とか、 基礎知識ゼロの状態だったわたしが、アハハウフフな気持ちで最初にさわり始めたのはPHP(Laravel)でした。 おそらく初学者の登竜門(?)であるToDoアプリを作り始めるやいなや ぶつかった最初の壁は、そう、タイトルにも冒頭にも書いたとおり、「変数って何なの???」というやつです。 それはそれはもうめちゃくちゃ検索しました。 変数とは 変数って何 変数とはつまり 変数 わからない 変数 意味 etc... あああああああ〜調べても調べても書いてあることが理解できない〜〜 user.php 'user_id' => $user_id; こんなふうに書かれててもどれが変数でどれがカラムでそれぞれがどういう動きをしているのかさっぱりわからない。 検索して出てくるサイトや記事を読めば、それが親切丁寧に書いてあることだけは理解できても 肝心の「で、変数って何なの???なんで定義してあげないといけないの???」が全く腑に落とせなかったのです。 (ついでに言うと、関数を自分で作るっていうのも意味がわからないぜ!と思ってました。) ■ 定義するっていうのはつまり 段々と、わたしの悩みは「変数って何なの」から「定義するって何!!!!ギャオーー」に変わっていきました。 ここで突然の自己紹介ですが、わたしには現在2歳の息子がいます。 わたしが定義のことでギャオついていた当時、息子はようやくいくつかの単語を喋るか喋らないかぐらいの年頃です。 そんなわたしと息子がYouTubeで色んな動物が出てくる動画を何気なく見ていたときのこと、 息子はとくにゾウさんが大好きだったので、アニメや実写などいくつか動画を見るなかでも、 ゾウさんが出てくるシーンは「どうあん!!(ゾウさん)どうあん!!」と大喜びだったのですが、 そこでわたしはふと疑問に思いました。 アニメのゾウさんと実写のゾウさん、冷静に考えたら全然違うくない??  と。 だって実写のゾウさんは別に水色とかピンク色じゃないし、にっこりした顔でもないし、 大体あの鳴き声ってパオーンっていう表現で合ってる?? なのに息子はアニメのゾウさんを見ても実写のゾウさんを見ても、どうやら同じくゾウさんだと認識してるっぽい。 鼻が長くて耳が大きくてひらひらしてて、ずんぐりむっくりした動物 をゾウだと思ってる。 ・ ・ ・ んん? もしやこれがつまり定義ってことなのでは??そうなのでは??? なんだか雷に打たれたような気持ちになって(というと少し大袈裟なんですが) 試しに息子に、「ボール持ってきて」とお願いしてみると、息子のお気に入りのボールを持ってきてくれました。 そこでようやく、変数もプログラミングもこれと同じことなんじゃないのかと思い始めるのです。 そのときのわたしの頭に浮かんだものをプログラミングのコード風(あくまでも風)に書きおこすとしたらこんな感じ。 my_son.php public function getFavoriteBall() { $おもちゃ箱 = 遊ぶものがたくさん入ってる箱; $ボール = 丸い形をした遊ぶもの; $おかあさん = いつも家にいてご飯をくれるアイツ; if ( $おもちゃ箱 のなかに $ボール があったら ) { $おかあさん に 渡す; } } そう、そうなのです。 プログラミングを始める前からずっと、知らず知らずのうちに、ありとあらゆるものが定義されている世界で生きていたし 自分自身でもいろんなものを定義して生きていたのです。 人生は定義だらけ。 生活するうえで必要なことは定義がなくては会話もままならないでしょう。 「おーい、いつも家にいてわたしのつくったごはんを食べる小さいひと〜、 あそこの四角い形のやつのなかに入っていて、あなたがよくあそんでいる丸い形のあそぶものを取ってきて」 なんてことになります。超面倒くさいです。 なるほど。定義、大事。 さてさて、こういったことをプログラミング上ではこちらの意図を伝える相手が人間ではなく機械なので、 察してもらうということができません。 仮に、「ねえねえ、アレ取ってきてくれない?」を人間とロボットの間で実現するためには、 - 「ねえねえ」という音を検知したら、ねえねえの後に続く指示を実行するとあらかじめ決めておく - 「アレ」とは何を指すのかをあらかじめ決めておく - 「取ってきてくれない?」で、どこから取ってきて、取ってきたものをどうしなければならないのかをあらかじめ決めておく このあたりを明確にしておく必要があります。 この「あらかじめ決めておく」がつまり、「定義する」ということです。 ■ 「定義する」はOK分かった、じゃあ変数は? 「ねえねえ、アレ取ってきてくれない?」を実現するために必要なことは上記で述べましたが、 「アレ取ってきてくれない?」以外にもロボットにお願いしたいことって色々あると思います。 「ねえねえ、エアコンつけて」 「ねえねえ、部屋の掃除して」 「ねえねえ、最新のヒット曲を再生して」などなど。 エアコンをつけるとは何か、部屋とは何か、掃除とは何か、最新とはいつからいつまでのことを指すのか、 そういった細かいことについてももちろん定義する必要がありますが、 それはそうと、 さきほど追加で挙げた例のためだけに、全く同じ「ねえねえ」を3回も書いてしまいました。 「ねえねえ」を「あのさぁ」に変更したくなったら、また「あのさぁ」を同じ回数書かなければなりませんよね。 正直面倒くさいし、 「ねえねえ」を「ねーねー」と書き間違えた箇所があったら、ロボットさんは厳密に指示された通り動きますから その書き間違えてしまった箇所は「ねえねえ」では動いてくれないので、意図どおり指示が通らなくなってしまいます。 長くなりましたが、ようやくここで変数の登場です。 どのように呼びかけるかについてを変数として定義しちゃえばいいんですよ。 PHP(Laravel)では変数の頭にドルマーク($)をつける決まり事がありまして、それに従って $呼びかけ  という変数を定義します。 hey.php $呼びかけ = ねえねえ; 「$呼びかけ、エアコンつけて」; 「$呼びかけ、部屋の掃除して」; 「$呼びかけ、最新のヒット曲を再生して」; という記述にしておけば、「ねえねえ」を「あのさぁ」に変更したくなっても、 hey.php $呼びかけ = あのさぁ; 「$呼びかけ、エアコンつけて」; 「$呼びかけ、部屋の掃除して」; 「$呼びかけ、最新のヒット曲を再生して」; このように、最初の1行だけ変更すれば済むため非常に効率が良く、書き間違い防止にもなります。 (注:ここではひとまず変数という概念を理解しやすいように日本語表記でコードっぽく書いていますが、実際には上記のように日本語表記では動きません) プログラミングにおいて変数や関数をどういう名前で定義するか、 それには、命名規則(名付けるための決まり事)が大切なようです。 たとえば、少し前にさかのぼって、2歳の息子とボールのくだりあたりで getFavoriteBall という名前の関数っぽいものを書きましたが、 ここに含まれる単語3つ get favorite ball の区切りをどう表記するかの決まり事です。 getFavoriteBall  単語の頭文字をそれぞれ大文字にする:キャメルケースと言います get_favorite_ball  単語の間を _ (アンダースコア)で繋ぐ:スネークケースと言います get-favorite-ball  単語の間を - (ハイフン)で繋ぐ:ケバブケースと言います ※その他及び詳細についてはここでは割愛します。検索してみると色々とわかりやすい記事がたくさんありますのでぜひご覧になってみてください。 命名規則には守らなければならないレベルがいくつかあって、 そのプログラミング言語での決まり事(守らないと大概エラーになる) 複数人でプロジェクトに携わる場合における、プロジェクト内での決まり事 (守らなくてもエラーは出ないかもしれないが可読性や保守性が低下し将来的にエラーを誘発する素因となりえる) 守らなければそもそもプログラムが動いてくれない、というレベルの決まり事と、 守らなくてもプログラムは動くけれども守った方が良い、というレベルの決まり事などがあります。 何かのプロジェクトに途中から参加する場合は 既存の記述がどのように命名されているかを見て、それに従っていけばきっとOKです。 自分1人でプログラミングする場合は、数ヶ月後に読み返してもそのコードを読み解けるかどうか?と考えて頂ければOKです。 このあたりの決まり事を守ったうえで、かつ、できるだけ誰が見ても分かりやすいように、を心がければ 変数の名前も、定数の名前も、関数の名前も、自由で良いと思います。 (注:PHP・Laravelを学習している上での所感です。ほかの言語では違うよ〜ということがあればぜひ教えてください。) とりあえず、まずは「ふーん、命名規則っていうのがあるんやな」ということを心に留めておいておけたら良いのではないでしょうか。 ■ 結論:変数とは 人間がプログラミング言語を用いてパソコンや機械に対して意図や指示を伝えるために、 「これはこういうことです」とするうえで無くてはならないものです。 今では、変数を定義しなかったらどうやってコードを書けばいいのか分からないとさえ感じます。 この結論に至るまでの道のりを今回は記事にしました。 長々とお読み頂きありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 7.* にbootstrapを導入する方法

Laravelにbootstapを導入する方法 まずは、自分の環境を確認する。 qiita.rb $ composer -v Composer version 2.1.11 2021-11-02 12:10:25 $ php artisan --v Laravel Framework 7.30.5 環境を確認できたら、実際にLaravelを組み込みましょう。 Laravel6~からbootstrapが使えなくなったので、自身で使えるようにしないといけません。 まずは以下のコードをターミナル上でコマンドしてみましょう。 qiita.rb $ composer require laravel/ui おそらくエラーが起きるのではないかと思います。 バージョンを指定して、インストールする必要があります。 私はLaravel7.30.5ですので、2系にあたります。 qiita.rb ///1系 $ composer require laravel/ui:1.* ///2系 $ composer require laravel/ui:2.* ///3系 $ composer require laravel/ui:3.* 実行した後は出力結果にある指示に従っていくだけです。 qiita.rb $ php artisan ui bootstrap Bootstrap scaffolding installed successfully. Please run "npm install && npm run dev" to compile your fresh scaffolding. ありがとうございました。参考にしていただけたら幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPの正規表現を具体例を見ながら紐解いてみる

業務で正規表現に触れる機会があったのですが全くと言っていいほど理解していなかったため、備忘も兼ねて改めて整理してみました。 本記事では正規表現の記法を詳述するものではなく、実際に使用される機会の多いパターンを紐解いていくことで、概要を把握することを目的とします。 より詳しい内容は各種リファレンス等をご参照ください。また今回はPHPでの記法になります。 そもそも正規表現って何? ネット上のいくつかの記事を参考にしたところ、共通して抽出できる言葉は以下のようなものでした。 『正規表現とは、いくつかの文字列を一つの形式で表現するための表現方法』 文面上では分かりづらいので具体例で考えてみようと思います。 例えば、果物を表すこれらの文字列を一つの形式で表現してみるとどのようなものになるでしょうか? apple pineapple melon Strawberry Orange 上記5つの文字列を正規表現で表記すると以下になります。 //果物を示す文字列を正規表現で表記 [a-z]+ 以下で説明していきます。 まず[a-z]は文字クラスと呼ばれるもので、角括弧 [ と ] 内に囲まれたいずれかの一文字にマッチします。その次に”+”は量子定止と呼ばれるもので、ある文字が1回以上の繰り返していることを示します。 したがってまとめると [a-z] → “a” ~ “z”の文字が +    → 1回以上繰り返すものにマッチする 文字列という形になります。 結果的に上記5つの果物の文字列を単一で表現できるという形になります。 実際によく使用される正規表現を紐解いてみる それでは実際に正規表現の具体例を見ていきます。 今回は正規表現の使い方の例を確認することが目的であるため、今回紹介する正規表現自体の脆弱性(Regular expression Denial of Service)等はスコープ外としております。 実際に使用される場合は、機能要件やセキュリティ等を鑑みる必要がありますのでご注意ください。  郵便番号 //郵便番号の正規表現 /^[0-9]{3}-[0-9]{4}$/ 正規表現 名称 役割 // デリミタ データを項目ごとに区切る時の「区切り文字」の中に正規表現のパターンを記述 ^ キャレット 文頭を示す $ ドルマーク 文末を示す [0-9] 大括弧内に数字 0-9までのいずれかの数値にマッチします。 {n} 中括弧内に任意の数値 文字の繰り返しを表します まとめると以下になります。 //正規表現の開始 /  // 文頭から0~9までの数字が3文字続く ^[0-9]{3}   //郵便番号を区切るハイフン - // 0~9までの数字が3文字続く [0-9]{3}   //正規表現の終了と文末を示す $/ メールアドレス /^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-])+$/ 上記と重複する内容は割愛致します。 今回新しく出てきた内容をピックアップするとこちらになります。 正規表現 名称 役割 + プラス 一回以上の繰り返し () 小括弧 グループ化:直前の文字ではなく直前のグループの繰り返しにマッチさせることができるようになります * アスタリスク 0回以上の繰り返し \ バックスラッシュ 直後のメタ文字をエスケープする。ここでは直後の’.’ピリオドをエスケープしています まとめると以下になります。 //正規表現の開始 / //文頭から小文字・大文字の英数字のみが1回以上繰り返される ^([a-zA-Z0-9])+  //@マークの直前では大文字・小文字の英数字と文字列”., _, -”が0回以上繰り返される ([a-zA-Z0-9\._-])*@ //上記の続きで@マーク直後から小文字・大文字の英数字のみが1回以上繰り返される ([a-zA-Z0-9])+  //大文字・小文字の英数字と文字列”., _, -”が0回以上繰り返される ([a-zA-Z0-9\._-])+ //正規表現の終了と文末を示す $/ まとめ 今回はPHPでの正規表現についてざっくりまとめてみました。 上記は正規表現の記法のほんの一部でしかないので詳細は各種リファレンスを参照ください。 また各言語によって記法も異なるのでご注意ください。 参照サイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

techpitのlaravel講座の手順通りにやっていたらTarget class [UserController] does not exist.が出た件

techpitのlaravel講座をやっていたら とあった。 しかし、ユーザーコントローラーファイルはちゃんとあるし、クラスもある 講座通り進めていたが、誤字などがあると思ったので、今度は講座のコードを完全コピペで試してみた はい、ダメでした 原因 私のlaravelのバージョンが8で、講座で使用しているlaravelのバージョンが6だった laravel8とlaravel6では、ルーティングの仕様が変わって違うことが判明(正確には8から変更) laravel7までのルーティング web.php Route::group(['prefix' => 'users', 'middleware' => 'auth'], function () { Route::get('show/{id}', 'UserController@show')->name('users.show'); }); laravel8までのルーティング仕様に変更 web.php Route::group(['prefix' => 'users', 'middleware' => 'auth'], function () { Route::get('show/{id}', [UserController::class, 'show'])->name('users.show'); }); これで、UserControlerのクラスであるshowを参照しますという意味になる しかし、これでも足りないみたいで以下の記述が必要になる web.php use App\Http\Controllers\UserController; //追記 Route::group(['prefix' => 'users', 'middleware' => 'auth'], function () { Route::get('show/{id}', [UserController::class, 'show'])->name('users.show'); }); これでユーザーコントローラーファイルを使いますよという意味になる。 これで、ルーティング通りにshow/{id}にアクセスすると 感想 laravelの仕様変更が原因とは思いもつかなかった laravel8でlaravel7以前の教材や動画を学習している場合気を付けなければいけないと感じた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel de Lambda

PHP Laravelをサーバーレス化する方法として、AWS SAMを使用した手順はAmazon Web Services ブログで公開されています。 今回はコンテナイメージ化することで、より簡単にAWS Lambda上で動かす手順を記載します。 前提 PHPをサーバーレス化するための必須ライブラリ bref 拡張機能 brefphp/extra-php-extensions Laravel用Package brefphp/laravel-bridge Laravelのセットアップ Laravelインストーラー composer global require laravel/installer プロジェクト作成 laravel new laravel-function ログ出力先として標準出力の追加 config/logging.php ... 'channels' => [ ... 'stdout' => [ 'driver' => 'monolog', 'level' => env('LOG_LEVEL', 'debug'), 'handler' => StreamHandler::class, 'formatter' => env('LOG_STDERR_FORMATTER'), 'with' => [ 'stream' => 'php://stdout', ], ], ], ... 必須ライブラリの追加 bref composer require bref/laravel-bridge --update-with-dependencies worker.phpの作成 SQSからイベントメッセージを受信するためのエントリーポイントを作成 php artisan vendor:publish --tag=serverless-worker aws composer require aws/aws-sdk-php-laravel composer require aws/aws-sdk-php config/aws.phpの作成 php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider" AWS用プロバイダ設定追加 config/app.php 'providers' => [ ... Aws\Laravel\AwsServiceProvider::class, ... ], 'aliases' => [ ... 'AWS' => Aws\Laravel\AwsFacade::class, ] Credentials defaultの認証情報を利用するため、不要な設定は削除 config/queue.php ... 'sqs' => [ 'driver' => 'sqs', // 'key' => env('AWS_ACCESS_KEY_ID'), // 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 'queue' => env('SQS_QUEUE', 'default'), 'suffix' => env('SQS_SUFFIX'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'after_commit' => false, ], ... 処理の実装 API routes/api.php ... // API 例 Route::get('/greeting', function () { return 'Hello World'; }); // 非同期Job呼び出し用 Route::get('/job', function (Request $request) { $message = $request->get("msg"); \App\Jobs\SimpleJob::dispatch($message); return 'OK'; }); Job SQS経由で非同期に実行するJob app/Jobs/SimpleJob.php <?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; class SimpleJob implements ShouldQueue { use Dispatchable; use InteractsWithQueue; use Queueable; use SerializesModels; /** @var string */ private $message; public function __construct(string $message) { $this->message = $message; } /** * Execute the job. * * @return void */ public function handle() { Log::info('Message: ' . $this->message); } } ローカル実行環境 localstack localstackの初期化用シェルを作成 docker/sqs/init.sh #!/bin/sh awslocal sqs create-queue --queue-name localstack_dead_letter_queue awslocal sqs create-queue --queue-name LaravelQueue \ --attributes '{"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-northeast-1:000000000000:localstack_dead_letter_queue\",\"maxReceiveCount\":3}"}' # Lambdaの作成 awslocal lambda create-function \ --function-name 'laravel-lambda-job-bridge' \ --runtime=provided.al2 \ --role=dummyrole \ --handler=worker.php awslocal lambda create-event-source-mapping \ --event-source-arn arn:aws:sqs:ap-northeast-1:000000000000:LaravelQueue \ --function-name "laravel-lambda-job-bridge" xdebug 設定ファイルを作成 docker/php/xdebug.ini [xdebug] xdebug.start_with_request=yes xdebug.client_host=host.docker.internal xdebug.client_port=9003 xdebug.log=/tmp/xdebug.log デバッグ用Dockerfile API用 debug.Dockerfile FROM bref/php-81-fpm-dev COPY --from=bref/extra-redis-php-81:0.11.19 /opt /opt COPY --from=bref/extra-xdebug-php-81:0.11.19 /opt /opt COPY docker/php/xdebug.ini /opt/bref/etc/php/conf.d/zz-xdebug.ini COPY --from=composer:2.1.12 /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer JOB用 jobs.debug.Dockerfile FROM bref/php-81 COPY --from=bref/extra-redis-php-81:0.11.19 /opt /opt COPY --from=bref/extra-xdebug-php-81:0.11.19 /opt /opt COPY docker/php/xdebug.ini /opt/bref/etc/php/conf.d/zz-xdebug.ini COPY --from=composer:2.1.12 /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer docker-compose docker-compose.yml version: "3.5" services: web: image: bref/fpm-dev-gateway ports: - '8000:80' volumes: - .:/var/task links: - php environment: HANDLER: public/index.php DOCUMENT_ROOT: public php: build: context: . dockerfile: debug.Dockerfile env_file: - .env.example environment: LOG_CHANNEL: stdout QUEUE_CONNECTION: sqs SQS_PREFIX: 'http://localstack:4566/000000000000' SQS_QUEUE: LaravelQueue AWS_DEFAULT_REGION: ap-northeast-1 XDEBUG_MODE: develop,debug PHP_IDE_CONFIG: serverName=docker volumes: - ~/.aws:/.aws - .:/var/task:ro # sqs localstack: image: localstack/localstack:latest environment: HOSTNAME_EXTERNAL: localstack DEFAULT_REGION: ap-northeast-1 DATA_DIR: /tmp/localstack/data SERVICES: sqs ports: - "4566:4566" volumes: - ./docker/sqs:/docker-entrypoint-initaws.d job: build: context: . dockerfile: jobs.debug.Dockerfile depends_on: - localstack env_file: - .env.example environment: LOG_CHANNEL: stdout QUEUE_CONNECTION: sqs SQS_PREFIX: 'http://localstack:4566/000000000000' SQS_QUEUE: LaravelQueue AWS_CONFIG_FILE: /.aws/config AWS_SHARED_CREDENTIALS_FILE: /.aws/credentials AWS_DEFAULT_REGION: ap-northeast-1 XDEBUG_MODE: develop,debug PHP_IDE_CONFIG: serverName=docker entrypoint: - php - artisan - queue:work volumes: - ~/.aws:/.aws - .:/var/task:ro ローカル実行 docker-compose up -d 動作確認 > curl 'http://localhost:8000/api/greeting' Hello World > curl 'http://localhost:8000/api/job?msg=Success' OK Dockerイメージの作成 Rest API用 Dockerfile bref/php-81-fpmを使用 Redisを利用する場合、brefphp/extra-php-extensionsから extra-redis-php-81を使用 今回は例示として追加 Dockerfile FROM bref/php-81-fpm COPY --from=bref/extra-redis-php-81:0.11.18 /opt /opt COPY . /var/task CMD [ "public/index.php" ] docker build -t {AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/laravel-api-function:latest . Job 用 jobs.Dockerfile bref/php-81を使用 Redisを利用する場合、brefphp/extra-php-extensionsから extra-redis-php-81を使用 今回は例示として追加 jobs.Dockerfile FROM bref/php-81 COPY --from=bref/extra-redis-php-81:0.11.18 /opt /opt COPY . /var/task CMD [ "worker.php" ] docker build -f jobs.Dockerfile -t {AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/laravel-jobs-function:latest . ECR dockerイメージを保存するリポジトリを作成 laravel-api-function aws ecr create-repository --repository-name laravel-api-function --region ap-northeast-1 laravel-jobs-function aws ecr create-repository --repository-name laravel-jobs-function --region ap-northeast-1 dockerイメージをリポジトリにプッシュ ECRログイン aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin {AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com リポジトリにプッシュ laravel-api-function docker push {AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/laravel-api-function:latest laravel-jobs-function docker push {AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/laravel-jobs-function:latest SQS 動作確認用のSQSキューを作成 aws sqs create-queue --queue-name LaravelQueue デプロイ CloudFormation API GatewayからLambda Functionを起動する CloudFormationファイルの作成 api.yaml AWSTemplateFormatVersion: "2010-09-09" Parameters: LogGroupName: Type: String Default: /aws/api-gateway/laravel FunctionName: Type: String Default: laravel-api-function QueueName: Type: String Default: LaravelQueue Resources: ApiFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Ref FunctionName MemorySize: 1024 Timeout: 300 Code: ImageUri: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/laravel-api-function:latest' ImageConfig: Command: - public/index.php PackageType: Image Environment: Variables: APP_ENV: development LOG_LEVEL: debug LOG_CHANNEL: stdout QUEUE_CONNECTION: sqs SQS_PREFIX: !Sub 'https://sqs.${AWS::Region}.amazonaws.com/${AWS::AccountId}' SQS_QUEUE: LaravelQueue Role: !GetAtt Role.Arn Role: Type: AWS::IAM::Role Properties: RoleName: RoleForLaravelApiFunction AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Sid: "" Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Path: / Policies: - PolicyName: LaravelApiFunctionPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*' - Effect: Allow Action: - sqs:SendMessage - sqs:GetQueueAttributes Resource: - !Sub 'arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${QueueName}' HttpAPI: Type: AWS::ApiGatewayV2::Api Properties: Name: !Sub '${AWS::StackName}-apigw' ProtocolType: HTTP DefaultStage: Type: AWS::ApiGatewayV2::Stage Properties: StageName: $default ApiId: !Ref HttpAPI AutoDeploy: true AccessLogSettings: DestinationArn: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${LogGroupName}' Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }' DependsOn: - ApiGatewayLog ApiGatewayLog: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Ref LogGroupName RetentionInDays: 3 GetGreeting: Type: AWS::ApiGatewayV2::Route Properties: RouteKey: "GET /api/greeting" ApiId: !Ref HttpAPI Target: !Join - "/" - - "integrations" - !Ref GETIntegration GetJob: Type: AWS::ApiGatewayV2::Route Properties: RouteKey: "GET /api/job" ApiId: !Ref HttpAPI Target: !Join - "/" - - "integrations" - !Ref GETIntegration GETIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref HttpAPI PayloadFormatVersion: "2.0" IntegrationType: AWS_PROXY IntegrationMethod: GET IntegrationUri: !GetAtt ApiFunction.Arn Permission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !Ref ApiFunction Principal: apigateway.amazonaws.com SourceArn: !Sub - 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpAPI}/*' - HttpAPI: !Ref HttpAPI CloudFormationデプロイ aws cloudformation deploy --template api.yaml --stack-name laravel-api-function --capabilities CAPABILITY_NAMED_IAM SQSをトリガーに起動する CloudFormationファイルを作成 jobs.yaml AWSTemplateFormatVersion: "2010-09-09" Parameters: FunctionName: Type: String Default: laravel-jobs-function QueueName: Type: String Default: LaravelQueue Resources: JobFunction: Type: "AWS::Lambda::Function" Properties: FunctionName: !Ref FunctionName MemorySize: 1024 Code: ImageUri: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/laravel-jobs-function:latest' ImageConfig: Command: - worker.php PackageType: Image Environment: Variables: APP_ENV: development LOG_LEVEL: debug LOG_CHANNEL: stdout QUEUE_CONNECTION: sqs SQS_PREFIX: !Sub 'https://sqs.${AWS::Region}.amazonaws.com/${AWS::AccountId}' SQS_QUEUE: !Ref QueueName Role: !GetAtt Role.Arn Role: Type: AWS::IAM::Role Properties: RoleName: RoleForLaravelJobFunction AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Sid: "" Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Path: / Policies: - PolicyName: LaravelJobFunctionPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*' - Effect: Allow Action: - sqs:ReceiveMessage - sqs:DeleteMessage - sqs:GetQueueAttributes Resource: - !Sub 'arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${QueueName}' SQSEvent: Type: AWS::Lambda::EventSourceMapping Properties: BatchSize: 10 EventSourceArn: !Sub 'arn:aws:sqs:ap-northeast-1:${AWS::AccountId}:${QueueName}' FunctionName: !GetAtt JobFunction.Arn Enabled: true CloudFormationデプロイ aws cloudformation deploy --template jobs.yaml --stack-name laravel-jobs-function --capabilities CAPABILITY_NAMED_IAM 動作確認 ApiEndpointの取得 > aws apigatewayv2 get-apis { "Items": [ { "ApiEndpoint": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com", "ApiId": "xxxxxxxxxx", "ApiKeySelectionExpression": "$request.header.x-api-key", "CreatedDate": "2021-12-02T00:00:00+00:00", "DisableExecuteApiEndpoint": false, "Name": "laravel-api-function-apigw", "ProtocolType": "HTTP", "RouteSelectionExpression": "$request.method $request.path", "Tags": {} } ] } apiの確認 /api/greeting > curl '{ApiEndpoint}/api/greeting' Hello World レスポンスとしてHello Worldが表示される jobの動作確認 /api/job > curl '{ApiEndpoint}/api/job?msg=Success' OK レスポンスとしてOKが表示される CloudWatch Logsの/aws/lambda/laravel-jobs-function に Message: Successのログが出力される まとめ PHP Laravelのコンテナイメージ化を行い、AWS Lambdaにデプロイ、動作確認するまでの手順を簡単に記載しました。 このまま業務に使用できるものではなく、実際にはVPCやRDSProxy等に接続するための設定、実装が必要になるでしょう。 また、Jobを非同期化するとしてもイベントメッセージがPHPに依存したJobクラスのシリアライズデータとなるため抽象化も難しく、APIとJobで実装をきれいに分けるのも困難です。 そのため、最適解ではありませんが、既存システムがPHP Laravelに依存しており、エンジニアに別の言語やフレームワーク等への移行を求める余裕がない場合、あるいはマイクロサービス化ほどの大げさなことにはしたくない場合、負荷を分散させる方法として手段の一つにはなると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[CentOS7] 古いバージョンのApacheとPHPを連携するまで

警告 この記事は、前回の記事 を読んだ前提で書いてます。 ご了承ください リンク はじめに この記事は[CentOS7]Apacheの古いバージョンの導入とデーモン化の続きです。 Apacheインストール終わったけど、PHP使いたくてもできない!!!!! ってことで一日使いました。無念。。 てか、デフォルトでできない分、普通の設定だとうまく動きません。なので、発生したインシデントと対応についてつらつら書きます。 経緯 先日上げた記事では、Apacheのインストール・デーモン化を行いました。 ウッキウキな僕はおもむろにPHPを記述。 Apacheを起動! ブラウザで確認!!! 何も出ない。 \omg/ yum で PHPをインストールしただけだと、もとからあるApacheに設定を吸われるっぽい(そりゃそう。) ってことで気合でどうにかしないといけません。 やったこと デフォルトのApacheの設定ファイル(httpd.conf)を見に行く →/usr/local/apache2と比較するため →よくわからん 「Apache PHP」と検索して一通り試す →動かない うーん困った。。。 とりあえず、PHPinfoを出したい、、、 PHPinfoはコマンドライン上では見える。ブラウザでは見えん。ってかPHP動いてないし、なんかダウンロードされるし。 解決策 困ったのでデフォルトのApacheのmoduleを見に行きました。場所はfindコマンドとかで探して。 どうやらPHPのモジュールがあってそれをうまく読み込めていない状況。 httpd.conf <IfModule !mod_php5.c> <IfModule prefork.c> LoadModule php7_module modules/libphp7.so </IfModule> </IfModule> <IfModule !mod_php5.c> <IfModule !prefork.c> LoadModule php7_module modules/libphp7-zts.so </IfModule> </IfModule> とりあえずこの辺をコピペ。 なんかびみょー 色々調べる。ふむふむ。 とりあえずできたコピペをこちらに /usr/local/apache2/conf/httpd.conf <Files ".user.ini"> <IfModule mod_authz_core.c> Require all denied </IfModule> <IfModule !mod_authz_core.c> Order allow,deny Deny from all Satisfy All </IfModule> </Files> AddType text/html .php DirectoryIndex index.php <FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> AddHandler phpX.X-script .htm .html <IfModule !mod_php5.c> <IfModule prefork.c> LoadModule php7_module modules/libphp7.so </IfModule> </IfModule> <IfModule !mod_php5.c> <IfModule !prefork.c> LoadModule php7_module modules/libphp7-zts.so </IfModule> </IfModule> そうそう。このLoadModuleってとこのmoduleは一応コピーしないとってことで、 cp -p /usr/lib64/httpd/modules/libphp7.so /usr/local/apache2/modules/ cp -p /usr/lib64/httpd/modules/libphp7-zts.so /usr/local/apache2/modules/ これでいけた。僕の場合。 あと、httpd -tSってコマンドがhttpd.confのエラーチェックなのでいっぱい使う。 なんか動かない場合(参考にならないかも) 前述しているように、デフォルトで入っているApacheがあります。httpd -tSコマンドを混在しないように消します。 sudo yum remove -y httpd apr apr-util httpd-tools そうすると、デーモン化したApacheが動かなくなるので、再度make installしてあげてください。 そうすれば、systemctlから起動できると思います。 PHPファイルがダウンロードされるんだけど! これはまじで糞だった。 意味わからんし。 まぁさっきのhttpd.confで治ったんだけど、一応使っているブラウザのCookieを削除しておきましょう。 多分治るはず。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

まだレビューでそんなやりとりしてるの?PHPStanとPHP-CS-Fixerを導入して楽しよう(Github Actionsを添えて)

はじめに 弁護士ドットコム Advent Calendar 2021 記念すべき1日目?(2年連続) 本記事はあくまでも、Laravel MeetUp Okinawa でお話しした内容を記事にしたものになります。 本題 突然ですが、レビューでこんな事を言われた/言った経験はないだろうか。 「インデント!!これもう指摘するの3回目!!」 「ここの変数未定義だし、ここも型合ってないよ!!」 …………… ………………………… ……………………………………… 指摘された側 はその場では反省して、気をつける事だろう。 しかし、所詮は人間。同じミスはしてしまう。 指摘する側 も同じことを注意するのは面白いものではないし、 何よりロジックや設計のレビューに集中してレビューしたい。 静的解析と自動整形を導入してみない? そんな時に 静的解析 と 自動整形 の導入を検討してみよう。 静的解析(PHPStan) プログラムコードを実行せずにドキュメントやソースコードなどのチェックによって誤りや脆弱性を検出するテスト手法。 それらをPHPで提供されているのが静的解析ツール(今回はPHPStan)です。 今回はLaravel専用のPHPStanのラッパーライブラリLarastanを使用します。 静的解析とは 仕様 プログラムを実行せずに解析される(ただしPHPstanは一部実行する) 未定義の変数/メソッド/Class/プロパティなどを検出 その他PHPDocの構文不備や分岐のチェックも メリット 静的に解析される箇所は網羅的にテストができる テストを書く必要がないのでコストが少ない 変数の未定義など細かいエラーが事前に分かるのでコードレビューの手間が省ける デメリット 無限ループなどは検出できない PHPDoc PHPDocに引数や戻り値に型を宣言することで(実際の型宣言ではない)色々なメリットがあります。 型を強くしていきたいけど、型宣言はちょっとハードル高いなぁ...という時に導入すると良いでしょう! コードの見通しが良くなる IDEの補完が効くようになる 静的解析ができる arrayの中身を指定できる(array) 型宣言本格導入前に気軽に導入できる /** * プロフィール情報を取得する * * @param string|null $name * @param integer $age * @return string|null */ public function getProfile($name = null, $age) { if (!$name) { return null; } return "名前: {$name} 年齢: {$age}"; } Levelや範囲などの設定 静的解析のレベルはプロジェクトによって柔軟に設定することができます。 このレベル設定によって、0から初めて徐々にレベルを上げることでより厳密にプロジェクトを静的解析していくことが可能です。 includes 設定ファイルの読み込み paths 対象ファイル level 静的解析のレベル 0 ~ 8(max) excludePaths 無視ファイル phpstan.neon includes: - ./vendor/nunomaduro/larastan/extension.neon parameters: paths: - app/ - database/ - tests/ level: max excludePaths: - ./*/*/FileToBeExcluded.php checkMissingIterableValueType: false 使い方 ライブラリをプロジェクトに入れたら以下のようなコマンドで実行できます。 ./vendor/bin/phpstan analyze 自動整形(PHP-CS-Fixer) コーディング規約を設定した基準沿って自動でコーディングを統一する機能。 その機能をPHPで提供されているのが PHP-CS-Fixer (他にもPHP_CodeSnifferなどがある) です。 PHP-CS-Fixer では公式で PSR-1 や PSR-2 他にも Symfonyコミュニティ の標準 などが用意されていて、それらを使うことも自身でカスタマイズして使用することができる。 また VSCode でプラグインも用意されており、保存時に自動整形することも可能です。 カスタマイズ 自動整形のルールは独自でカスタマイズも可能です。 ver3.0.0 からはphpファイルになりました。 Finder::create() 対象ファイル setRiskyAllowed リスクが高い変更の許可 setRules カスタマイズするルール設定を記述 .php-cs-fixer.dist.php <?php declare(strict_types=1); $finder = PhpCsFixer\Finder::create() ->in([ __DIR__ . '/app', __DIR__ . '/config', __DIR__ . '/database/factories', __DIR__ . '/database/seeders', __DIR__ . '/routes', __DIR__ . '/tests', ]); $config = new PhpCsFixer\Config(); return $config ->setRiskyAllowed(true) ->setRules([ '@PhpCsFixer:risky' => true, 'array_syntax' => ['syntax' => 'short'], 'blank_line_after_opening_tag' => true, 'cast_spaces' => ['space' => 'single'], ]) ->setFinder($finder); 使い方 ライブラリをプロジェクトに入れたら以下のようなコマンドで実行できます。 整形箇所のピックアップ(実際に整形はされない) ./vendor/bin/php-cs-fixer fix -v --diff --dry-run 自動整形を適用する ./vendor/bin/php-cs-fixer fix -v --diff 静的解析 と 自動整形 を導入できました! おめでとうございます。 これによって実装者はレビューを出す前に細かなエラーに気付いて修正する事ができます! これでお互い細かなレビューを指摘する/される必要がなくなリました!やったね! ただもっと楽がしたい! 静的解析 は 自動整形 を導入できたけど、ローカルで実行し忘れたままレビューに投げちゃった(ToT) なんて事もあるでしょう。 そういう時は CI で自動に実行するようにしましょう。 CI(Github Actions) CIとは、Continuous Integrationの略で、継続的インテグレーションと呼ばれていて、 開発、テスト、リリースのサイクルが継続的に行われていく様子の事であり、それらを円滑に使用出来る様にしたものがCIツールです。 今回は Github Actions を使用しますが、CIのツールは Github Actions だけでなく、複数のツールが存在しています(Circle CIなど) Github Actions を使うメリットは無料(privateリポジトリは月2,000時間まで)という点と、普段利用している Github内のプロジェクトに .github/workflows/ ディレクトリを用意して設定ファイルを書くだけで利用できる手軽さにあります。(個人的見解) 他にも公式が用意しているテンプレートを簡単に使用することもできます。 設定方法 /.github/workflows/ にyaml形式で記入する on: CIが走るタイミングを決める jobs: stepsの集まり steps: jobを構成するAction などなど ここまで学んだ静的解析と自動整形をCIで設定してみる PHPStan マスターに対してプルリクエスト、マージが行われたタイミングでテストが走るように設定。 /.github/workflows/larastan.yml PHP-CS-Fixer こちらもLarastanと同様のトリガーでテストを実行します。 今回は dry-run で差分を出力までしかしていません。 自動整形を適用したい場合は一番下の run を ./vendor/bin/php-cs-fixer fix -v --diff に差し替えてください。 /.github/workflows/php-cs-fixer.yml CIであえて落ちる実装 あえてテストが落ちるように実装して、CIが走るようにプルリクを作ってみました。 <?php declare(strict_types=1); namespace App\Http\Controllers; use Illuminate\Http\Request; class ExampleController extends Controller { /** * @param int $id * @return int */ public function index(string $id): int { echo $test; $array = array(); return $id; } } プルリクを作成してCIが動いているのを見てみる 先ほどの実装でプルリクを作ってみた。 Github Actions を使っていると、Merge pull request の上にテストが走っているのが分かる。 テストが落ちると下の図のように、どのテストが落ちていて、Merge pull request が不活性になっているのが確認できる。 静的解析のテスト結果 確認すると以下の内容で、怒られているのが確認できる。 引数の型不一致 戻り値の型不一致 未定義の変数の使用 自動整形のテスト結果 確認すると以下の内容で、怒られているのが確認できる。 declareの改行 namespaceの改行 array()の使用 修正して再度プッシュ 先ほどの内容を修正して、再度プッシュしてみました。 そうするとテストが全部通って、Merge pull requestが活性化しているのが確認できました。 これでプルリクでレビュワーをアサインする前に自動的に細かいレビューで指摘されることがなくなりました!やったね! 最後に これまで学んだ内容は以下のリポジトリに公開していますので、ご自由にお使いください。 明日は @hkano さんの OpenSearch を使ってみる です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1年半振りのメジャーバージョンアップ(予定)!Laravel9の新機能ピックアップ!

Laravel Advent Calendar 2021 1日目の投稿です。 来月(2022年1月)、1年半ぶりのLaravelのメジャーバージョンアップするのでLaravel9の主要な変更点をまとめてみました。 リリース日 Laravel 8: 2020年9月 Laravel 9: 2022年1月(予定) Laravel 10: 2023年1月(予定) Laravel 11: 2024年1月(予定) Symfony6.0が2021年11月30日にリリースされました。それに伴ってLaravel 9のリリースが2022年1月に延期されています。 また、Laravel 9以降は半年周期のメジャーリリースが1年周期になっています。 Version PHP (*) Release Bug Fixes Until Security Fixes Until 6 (LTS) 7.2 - 8.0 September 3rd, 2019 January 25th, 2022 September 6th, 2022 7 7.2 - 8.0 March 3rd, 2020 October 6th, 2020 March 3rd, 2021 8 7.3 - 8.1 September 8th, 2020 July 26th, 2022 January 24th, 2023 9 (LTS) 8.0 - 8.1 January 25th, 2022 January 30th, 2024 January 28th, 2025 10 8.0 - 8.1 January 24th, 2023 July 30th, 2024 January 28th, 2025 インストール要件 最低でも PHP8.0 以上である必要があります。 Laravel 9の内部でSymfony6.0が利用されており、PHP8.0が最小要件があるためLaravel 9にも同じ制限が適用されます。 新機能ピックアップ Anonymous Stub Migrations Laravel v8.37.0 でクラス名の衝突を防ぐために匿名マイグレーション機能がリリースされました。 Laravel 9.xでは php artisan make:migration 実行時に生成されるファイルが匿名マイグレーションがデフォルトとなります。(Laravel8.xではデフォルトのマイグレーションテンプレートはクラス名付きで生成されますが、匿名マイグレーションは利用可能です。) use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('people', function (Blueprint $table) { $table->string('first_name')->nullable(); }); } }; これにより名前被りを気にせずマイグレーションファイルを作成できます。 マイグレーションファイル名は日付プレフィックスが付くので同名ファイルでも問題ありません。 また、稀によく発生していたマイグレーションクラスをリネームしてオートローダーが壊れる問題もこれで解消されそうです。 新しくクエリビルダーインターフェイスが追加 Illuminate\Database\Eloquent\Relations Illuminate\Database\Eloquent\Builder Illuminate\Database\Query\Builder これらのクエリビルダークラス群が1つのインターフェース Illuminate\Contracts\Database\QueryBuilder と契約しました。 文字列関数の内部実装の変更 最小要件がPHP8.0ということで、下記の関数の内部実装が変更されています。 Str::contains(); Str::startsWith(); Str::endsWith(); str_contains()、str_starts_with() および str_ends_with() 関数が利用されています。 現時点では特に非推奨となっていませんが、PHPの標準関数で実現できるので今後はもしかしたら非推奨になる関数かもしれませんね。 SwiftMailerからSymfonyMailerへ SwiftMailerが非推奨となり、Laravel9ではSymfonyMailerを使用するように変更されています。 lang ディレクトリがトップレベルへ Laravel8までは resources/lang でしたがLaravel9からトップレベルへ移動されました。 Flysystem v2 AWS S3をLaravelで操作したい時に使うライブラリthephpleague/flysystem-aws-s3-v3 v2系はLaravel8で動作しませんでしたが、Laravel9からv2系がサポートされます。 アップグレードの際はご注意ください。 https://github.com/laravel/framework/pull/33612 https://qiita.com/ucan-lab/items/61903ce10a186e78f15f Laravel インストーラにAPIオプションの追加 $ laravel new foo --api HTMLを返さないAPIシステムのためのapiオプションがLaravelインストーラに追加されるそうです。 css, js関連ファイルが削除されたLaravelプロジェクトテンプレートを構築します。 (管理画面はやっぱり簡単なHTMLを返したいとかありそう...笑 簡単に戻せるならアリかな?) Laravel8で追加された新機能 Laravel8.xで新しく追加された機能で気になったものをご紹介します。 Eloquent N+1検知機能 Laravel v8.43.0 でN+1検知機能がしれっと追加されていました。 N+1クエリーがあると例外が発生するため開発プロセスの初期段階でN+1クエリーを発見できます。 https://laravel-news.com/disable-eloquent-lazy-loading-during-development https://github.com/laravel/framework/pull/37363 https://github.com/laravel/framework/releases/tag/v8.43.0 Enum型のサポート Laravel v8.71.0 でEnum型を便利に扱えるようにキャスト機能やクエリー周りのサポートが行われています。 https://github.com/laravel/framework/pull/39608 https://github.com/laravel/framework/pull/39492 https://github.com/laravel/framework/pull/39597 https://github.com/laravel/framework/releases/tag/v8.71.0 https://github.com/laravel/framework/releases/tag/v8.70.0 参考 https://laravel-news.com/laravel-9 https://blog.laravel.com/laravel-9-release-date
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1年半振りのメジャーバージョンアップ!Laravel9の新機能ピックアップ!

Laravel Advent Calendar 2021 1日目の投稿です。 来月、1年半ぶりのLaravelのメジャーバージョンアップするのでLaravel9の主要な変更点をまとめてみました。 リリース日 Laravel 8: 2020年9月 Laravel 9: 2022年1月(予定) Laravel 10: 2023年1月(予定) Laravel 11: 2024年1月(予定) Symfony6.0が2021年11月30日にリリースされました。それに伴ってLaravel 9のリリースが2022年1月に延期されています。 また、Laravel 9以降は半年周期のメジャーリリースが1年周期になっています。 インストール要件 最低でも PHP8.0 以上である必要があります。 Laravel 9の内部でSymfony6.0が利用されており、PHP8.0が最小要件があるためLaravel 9にも同じ制限が適用されます。 新機能ピックアップ Anonymous Stub Migrations Laravel v8.37.0 でクラス名の衝突を防ぐために匿名マイグレーション機能がリリースされました。 Laravel 9.xでは php artisan make:migration 実行時に生成されるファイルが匿名マイグレーションがデフォルトとなります。(Laravel8.xではデフォルトのマイグレーションテンプレートはクラス名付きで生成されますが、匿名マイグレーションは利用可能です。) use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('people', function (Blueprint $table) { $table->string('first_name')->nullable(); }); } }; これにより名前被りを気にせずマイグレーションファイルを作成できます。 マイグレーションファイル名は日付プレフィックスが付くので同名ファイルでも問題ありません。 また、稀によく発生していたマイグレーションクラスをリネームしてオートローダーが壊れる問題もこれで解消されそうです。 新しくクエリビルダーインターフェイスが追加 Illuminate\Database\Eloquent\Relations Illuminate\Database\Eloquent\Builder Illuminate\Database\Query\Builder これらのクエリビルダークラス群が1つのインターフェース Illuminate\Contracts\Database\QueryBuilder と契約しました。 文字列関数の内部実装の変更 最小要件がPHP8.0ということで、下記の関数の内部実装が変更されています。 Str::contains(); Str::startsWith(); Str::endsWith(); str_contains()、str_starts_with() および str_ends_with() 関数が利用されています。 現時点では特に非推奨となっていませんが、PHPの標準関数で実現できるので今後はもしかしたら非推奨になる関数かもしれませんね。 SwiftMailerからSymfonyMailerへ SwiftMailerが非推奨となり、Laravel9ではSymfonyMailerを使用するように変更されています。 lang ディレクトリがトップレベルへ Laravel8までは resources/lang でしたがLaravel9からトップレベルへ移動されました。 Flysystem v2 AWS S3をLaravelで操作したい時に使うライブラリthephpleague/flysystem-aws-s3-v3 v2系はLaravel8で動作しませんでしたが、Laravel9からv2系がサポートされます。 アップグレードの際はご注意ください。 https://github.com/laravel/framework/pull/33612 https://qiita.com/ucan-lab/items/61903ce10a186e78f15f Laravel8で追加された新機能 Laravel8.xで新しく追加された機能で気になったものをご紹介します。 Eloquent N+1検知機能 Laravel v8.43.0 でN+1検知機能がしれっと追加されていました。 N+1クエリーがあると例外が発生するため開発プロセスの初期段階でN+1クエリーを発見できます。 https://laravel-news.com/disable-eloquent-lazy-loading-during-development https://github.com/laravel/framework/pull/37363 https://github.com/laravel/framework/releases/tag/v8.43.0 Enum型のサポート Laravel v8.71.0 でEnum型を便利に扱えるようにキャスト機能やクエリー周りのサポートが行われています。 https://github.com/laravel/framework/pull/39608 https://github.com/laravel/framework/pull/39492 https://github.com/laravel/framework/pull/39597 https://github.com/laravel/framework/releases/tag/v8.71.0 https://github.com/laravel/framework/releases/tag/v8.70.0 参考 https://laravel-news.com/laravel-9 https://blog.laravel.com/laravel-9-release-date
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP8.1】PHP8.1がリリースされたので新機能全部やる

PHP8.1 / PHP8.0 / PHP7.4 2021/11/26にPHP8.1.0がリリースされました。 大きな新機能については、PHP8.0以降公開されるようになったランディングページで見ることができます。 ここでは、概要ではなくUPGRADINGに載っている変更点を全部見て回ることにします。 Backward Incompatible Changes 下位互換性のない変更点。 PHPコア Access to the $GLOBALS array is now subject to a number of restrictions $GLOBALSの内部処理を変更します。 $a = 1; $globals = $GLOBALS; // 値をコピー $globals['a'] = 2; var_dump($a); // PHP8.1 int(1) // PHP8.0 int(2) $GLOBALSは値をコピーしただけのはずなのにリファレンスになったりといった特殊な仕様がありました。 このせいで内部構造が複雑になり、パフォーマンスも劣化していました。 PHP8.1では、$GLOBALSを普通の変数と同じように扱うようにします。 Passing null to a non-nullable argument of a built-in function is deprecated 内部関数へのnullの引き渡しに関するルール変更です。 strlen(null); // PHP8.1 Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated // PHP8.0 エラー出ない strlenの引数はstringですが、これまではnullを渡しても何もエラーが出ませんでした。 PHPは元々型に緩かったという経緯もあり、内部関数への引数には甘めの判定をしていました。 それを徐々に厳しくしていく変更です。 PHP9ではユーザ定義関数と同様、TypeErrorになる予定です。 inherited method will now share static variables with the parent method. 静的変数の継承時の挙動変更です。 class A{ public static function counter(){ static $counter = 0; $counter++; return $counter; } } class B extends A{} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(3) PHP8.0までint(1) var_dump(B::counter()); // int(4) PHP8.0までint(1) 何故かこれまで、静的変数は継承したときに別の変数になっていたのですが、今後は同じになります。 変更後はクラス変数と同じ挙動です。 Most non-final internal methods now require overriding methods to declare a compatible return type ビルトインクラスの返り値の型の厳格化です。 class MyDateTime extends DateTime{ public function modify(string $modifier):int{ return 1; } } $dt = new MyDateTime(); $dt->modify('modifier'); // PHP8.1 Deprecated: Return type of MyDateTime::modify(string $modifier): int should either be compatible with DateTime::modify(string $modifier): DateTime|false // PHP8.0 エラー出ない DateTime::modify()の返り値はDateTime|falseですが、extends時に別の型を指定しても動作していました。 これが禁止されます。 ユーザ定義クラスでは最初からFatal Errorですが、ビルトインクラスは互換性のため特別に緩くしてありました。 今後は徐々にユーザ定義クラスと揃えていくということです。 互換性などの問題で今後も異なる返り値を使い続けたい場合は、アトリビュート#[ReturnTypeWillChange]で黙らせることができます。 Fileinfo The fileinfo functions now accept and return, respectively, finfo objects instead of resources finfo_openなどの関数は、これまでリソースを返していたのがfinfoオブジェクトを返すようになりました。 var_dump(finfo_open(FILEINFO_NONE)); // PHP8.1 object(finfo)#1 (0) {} // PHP8.0 resource(4) of type (file_info) 他のFileinfo関数はこれまでと同じ書き方で透過的に動作します。 is_resourceでチェックしている場合は修正が必要です。 FTP The FTP functions now accept and return, respectively, FTP\Connection objects instead of resources ftp_connectなどの関数は、これまでリソースを返していたのがFTP\Connectionオブジェクトを返すようになりました。 他のFTP関数はこれまでと同じ書き方で透過的に動作します。 IMAP The IMAP functions now accept and return, respectively, IMAP\Connection objects instead of resources imap_openなどの関数は、これまでリソースを返していたのがIMAP\Connectionオブジェクトを返すようになりました。 他のIMAP関数はこれまでと同じ書き方で透過的に動作します。 LDAP The LDAP functions now accept and return, respectively, LDAP\Connection objects instead of "ldap link" resources ldap_connectなどの関数は、これまでリソースを返していたのがLDAP\Connectionオブジェクトを返すようになりました。 他のLDAP関数はこれまでと同じ書き方で透過的に動作します。 The LDAP functions now accept and return, respectively, LDAP\Result objects instead of "ldap result" resources ldap_listなどの関数は、これまでリソースを返していたのがLDAP\Resultオブジェクトを返すようになりました。 他のLDAP関数はこれまでと同じ書き方で透過的に動作します。 The LDAP functions now accept and return, respectively, LDAP\ResultEntry objects instead of "ldap result entry" resources ldap_first_entryなどの関数は、これまでリソースを返していたのがLDAP\ResultEntryオブジェクトを返すようになりました。 他のLDAP関数はこれまでと同じ書き方で透過的に動作します。 MySQLi mysqli_fetch_fields() and mysqli_fetch_field_direct() will now always return zero for max_length. mysqli_fetch_fieldsおよびmysqli_fetch_field_directの返り値のうち、max_lengthは常に0になります。 そもそも結果セットにおけるフィールドの最大幅って何だ。 The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect. 定数MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTHは何の意味も持たなくなりました。 The MYSQLI_STORE_RESULT_COPY_DATA option no longer has an effect. 定数MYSQLI_STORE_RESULT_COPY_DATAは何の意味も持たなくなりました。 The default error handling mode has been changed from "silent" to "exceptions". mysqliのエラーモードのデフォルトがExceptionになりました。 Classes extending mysqli_stmt::execute() will be required to specify the additional parameter now. mysqli_stmt::executeに実行時引数引き渡しができるようになりました。 // mysqli 事前渡し $stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)'); $stmt->bind_param('ss', $id, $name); $stmt->execute(); // mysqli 実行時渡し $stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)'); $stmt->execute([$id, $name]); PDOStatement::execute()と同じ使い方ができるようになります。 mysqli::connect() will now return true instead of null on success. mysqli::connect()は成功時にtrueを返すようになりました。 これまでは何故かnullでした。 MySQLnd The mysqlnd.fetch_data_copy ini setting has been removed. ini設定mysqlnd.fetch_data_copyが削除されました。 ただしユーザから見える挙動に変化はありません。 OpenSSL EC private keys will now be exported in PKCS#8 format ECの秘密鍵が、他の鍵と同じくPKCS#8形式でエクスポートされるようになりました。 openssl_pkcs7_encrypt() and openssl_cms_encrypt() will now default to using AES-128-CBC openssl_pkcs7_encryptとopenssl_cms_encryptの暗号化アルゴリズムのデフォルト値がAES-128-CBCになりました。 これまではRC2-40でしたが、これは脆弱なのでOpenSSL3.0ではデフォルトでは無効化されています。 PDO PDO::ATTR_STRINGIFY_FETCHES now also stringifies values of type bool to "0" or "1". PDOの設定PDO::ATTR_STRINGIFY_FETCHESは、bool値を"0"か"1"にするようになりました。 これまではbool値は変換しませんでした。 Calling bindColumn() with PDO::PARAM_LOB will now consistently bind a stream result PDOStatement::bindColumn()の引数に型PDO::PARAM_LOBを渡すと、データが必ずストリームに入ってくるようになりました。 これまではデータベースドライバ等によってストリームだったり文字列だったりすることがありました。 PDO MySQL Integers and floats in result sets will now be returned using native PHP types when using emulated prepared statements. プリペアドステートメントを使った場合、返ってきたint型・float型の結果はPHPのint型・float型になりました。 これまではMySQL側の型に関わらず返り値は常に文字列型でした。 PDO SQLite Integers and floats in results sets will now be returned using native PHP types. 返ってきたint型・float型の結果はPHPのint型・float型になりました。 PgSQL The PgSQL functions now accept and return, respectively, \PgSql\Connection objects instead of "pgsql link" resources. pg_connectなどの関数は、これまでリソースを返していたのがPgSql\Connectionオブジェクトを返すようになりました。 The PgSQL functions now accept and return, respectively, \PgSql\Result objects instead of "pgsql result" resources. pg_queryなどの関数は、これまでリソースを返していたのがPgSql\Resultオブジェクトを返すようになりました。 The PgSQL functions now accept and return, respectively, \PgSql\Lob objects instead of "pgsql large object" resources. pg_lo_openなどの関数は、これまでリソースを返していたのがPgSql\Lobオブジェクトを返すようになりました。 Phar To comply with the ArrayAccess interface, Phar::offsetUnset() and PharData::offsetUnset() no longer return a boolean. Phar::offsetUnset()およびPharData::offsetUnset()は、これまでtrue/falseを返していたのが値を返さなくなりました。 オーバーライドしているhttps://www.php.net/manual/ja/class.arrayaccess.phpに揃えたものです。 $p = new Phar('./my.phar'); var_dump($p->offsetUnset('a')); // PHP8.1 NULL // PHP8.0 true PSpell The PSpell functions now accept and return, respectively, PSpell\Dictionary objects instead of "pspell" resources. pspell_newなどの関数は、これまでリソースを返していたのがPSpell\Dictionaryオブジェクトを返すようになりました。 The PSpell functions now accept and return, respectively, PSpell\Config objects instead of "pspell config" resources. pspell_new_configなどの関数は、これまでリソースを返していたのがPSpell\Configオブジェクトを返すようになりました。 Standard version_compare() no longer accepts undocumented operator abbreviations. version_compare関数は、これまで第三引数の比較演算子に非公式な引数!、l・gなどを受け付けていたのですが、これが禁止されました。 これはドキュメント化されておらず、ユーザノートにも記載はなく、そもそも知ってる人が何人いたのだろうというレベルの謎機能です。 var_dump(version_compare(PHP_VERSION, '8.1.0rc5', 'l')); // PHP8.1 PHP Fatal error: Uncaught ValueError: version_compare(): Argument #3 ($operator) must be a valid comparison operator // PHP8.0 true 今後はlではなくltもしくは<と記載しなければなりません。 しかし、これが実際に影響する人は存在するのでしょうか。 htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode() and get_html_translation_table() now use ENT_QUOTES | ENT_SUBSTITUTE rather than ENT_COMPAT by default. htmlspecialchars()をはじめとした各関数の、変換フラグのデフォルト値がENT_QUOTES | ENT_SUBSTITUTEになりました。 これまでのデフォルト値はENT_COMPATであり、シングルクォートは変換されませんでした。 var_dump(htmlspecialchars('a"b\'c')); // PHP8.1 a&quot;b&#039;c // PHP8.0 a&quot;b'c これまでの初期値がおかしかった案件。 debug_zval_dump() will now print reference wrappers with their refcount, instead of only prepending a "&" to the value. debug_zval_dump()は、参照値に参照カウントを表示するようになりました。 <?php $r = 1; $a = [&$r]; debug_zval_dump($a); // PHP8.1 array(1) refcount(2){ [0]=> reference refcount(2) { int(1) } } // PHP8.0 array(1) refcount(2){ [0]=> &int(1) } 細かすぎてわからない変更。 debug_zval_dump() will now print "interned" instead of a dummy refcount of one for interned strings and immutable arrays. debug_zval_dump()は、参照カウントが不要なところではinternedを表示するようになりました。 $a = "string"; debug_zval_dump($a); // PHP8.1 string(6) "string" interned // PHP8.0 string(6) "string" refcount(1) これまで表示されていたのが謎です。 SPL SplFixedArray will now be JSON encoded like an array. SplFixedArrayのJSONエンコード方式が配列と同じになりました。 var_dump(json_encode([1, 2])); var_dump(json_encode(SplFixedArray::fromArray([1, 2]))); // PHP8.1 "[1]", "[1]" // PHP8.0 "[1]", "{"0":1}" これまで異なっていたのが謎。 New Features 新機能。 Core It is now possible to specify octal integer by using the explicit "0o"/"0O" prefix 8進数を接頭辞0oで表現できるようになりました。 var_dump(0o10); // PHP8.1 int(8) // PHP8.0 Parse error: syntax error, unexpected identifier "o10" これまで8進数だけ010という謎形式だったものを2進数・16進数と合わせたものです。 既存の形式も当面の間は有効であり、非推奨になる予定はありません。 Added support for array unpacking with strings keys 文字列キーの配列をアンパックできるようになります。 var_dump([...['a'=>1], ...['a'=>2]]); // PHP8.1 ['a'=>2] // PHP8.0 Fatal error: Cannot unpack array with string keys Added support for enumerations. 列挙型が追加されました。 enum Suit : string{ case Hearts = 'H'; case Diamonds = 'D'; case Clubs = 'C'; case Spades = 'S'; } var_dump(Suit::Diamonds, Suit::Diamonds->name, Suit::Diamonds->value); // enum(Suit::Diamonds), "Diamonds", "D" 個別にメソッドを実装したりも可能で、様々な遊び甲斐がありそうな機能です。 Added support for never return type never型が追加されました。 function foo():never{ exit; } 常にexitしたり常に例外を吐くような、呼び出し元に帰らない型です。 Added support for fibers. Fiberが追加されました。 PHPのユーザサイドで非同期処理を書けるようになる画期的な機能です。 $fiber = new Fiber(function (): void { $value = Fiber::suspend('fiber'); echo "レジュームした。$value: ", $value, "\n"; }); $value = $fiber->start(); echo "一時停止した。$value: ", $value, "\n"; $fiber->resume('test'); とはいえPHPでの実装は最低限必要な機能に抑えられているため、実際に使いこなすにはライブラリの登場を待ったほうがいいかもしれません。 It is now possible to use "new ClassName()" expressions as parameter default values 引数デフォルト値でnewできるようになります。 class Test { public function __construct( private Logger $logger = new NullLogger, ) {} } これまではいったんnullなどで受け取ってから、nullであればnewするといった一手間が必要でした。 また、これはRFCには全く書かれていないのですが、defineにオブジェクトを渡せるようになりました。 define('HOGE', new stdClass()); // PHP8.1 エラー出ない // PHP8.0 PHP Fatal error: Uncaught TypeError: define(): Argument #2 ($value) cannot be an object, stdClass given 全く関係なさそうな話なのに唐突にここに書かれているのは、処理を共通で使っているから副作用でそうなったとかそんなかんじなのですかね。 Closures for callables can now be created using the syntax myFunc(...), Closure::fromCallableの糖衣構文です。 // 同じ myFunc(...); Closure::fromCallable('myFunc'); 前者と後者は全く同じ意味になります。 ...は省略ではなくこのままの文字です。 File uploads now provide an additional full_path key ファイルのアップロード時に、$_FILES['full_path']が追加されました。 webkitdirectoryでディレクトリごとアップロードした際に、ディレクトリを取り出せるようにするものです。 It is now allowed to specify named arguments after an argument unpack 引数アンパックの後ろに名前付き引数を追加することができるようになりました。 foo(...[1], named: "str"); function foo(...$args){ var_dump($args); // [1, "named"=>"str"] } これまでは引数アンパックと名前付き引数を組み合わせることはできませんでした。 逆のfoo(named: $arg, ...$args);はPHP8.1でもエラーになります。 Added support for intersection types. 交差型が追加されました。 function foo(Traversable&Countable $arg){ } foo(new ArrayIterator()); // エラー出ない foo(new DirectoryIterator('.')); // Fatal error: Uncaught TypeError: foo(): Argument #1 ($arg) must be of type Traversable&Countable, DirectoryIterator given 型のANDです。 Traversable&Countableであれば、TraversableかつCountableの型しか受け付けません。 Added support for the final modifier for class constants. finalクラス定数が追加されました。 class FOO{ final public const HOGE = 1; } class BAR extends FOO{ public const HOGE = 2; } // Fatal error: BAR::HOGE cannot override final constant FOO::HOGE finalのついたクラス定数は上書きできなくなります。 Added support for readonly properties. readonlyアクセス修飾子が追加されました。 class Test { public readonly string $name; public function setName(string $name) { $this->name = $name; } } $t = new Test(); $t->setName('a'); // OK $t->setName('b'); // Fatal error: Uncaught Error: Cannot modify readonly property Test::$name $t = new Test(); $t->name = 'a'; // Fatal error: Uncaught Error: Cannot initialize readonly property Test::$name from global scope 内部からは一回だけ書き込み可能ですが、一度書き込んだら上書きはできません。 外部からは一切書き込み不可能です。 極めてよくある『読まれてもいいけど書き込ませたくない』という要望へのソリューションです。 Curl Added CURLOPT_DOH_URL option. 定数CURLOPT_DOH_URLが追加されました。 libcurlのラッパーです。 DNS over HTTPSに対応したDNSサーバのURLを指定します。 これで何がうれしいかというと、DNSの中間者攻撃を防ぐことができます。 Added certificate blob options when for libcurl >= 7.71.0 定数CURLOPT_ISSUERCERT_BLOB・CURLOPT_PROXY_ISSUERCERT・CURLOPT_PROXY_ISSUERCERT_BLOB・CURLOPT_PROXY_SSLCERT_BLOB・CURLOPT_PROXY_SSLKEY_BLOB・CURLOPT_SSLCERT_BLOB・CURLOPT_SSLKEY_BLOBが追加されました。 これらもlibcurlに追加された定数のラッパーです。 Added CURLStringFile, which can be used to post a file from a string rather than a file ファイルのアップロード用にCURLStringFileクラスが追加されました。 既存のCURLFileはファイルの実体を指定する必要があって面倒だったのですが、CURLStringFileは文字列を直接ファイルとしてアップロードできます。 $file = new CURLStringFile($data, 'filename.txt', 'text/plain'); curl_setopt($curl, CURLOPT_POSTFIELDS, ['file' => $file]); 中身が$dataのファイルが、filename.txtという名前でアップロードされます。 FPM Added openmetrics status format. openmetricsフォーマットが追加されました。 PrometheusがFPMの情報を取得するのに使えるらしいですが、なんのことだかよくわからない。 Added new pool option for the dynamic process manager called pm.max_spawn_rate. プールオプションpm.max_spawn_rateが追加されました。 Apacheのpreforkみたいな話ですかね? そもそもFPMってなんなんだ。 GD Avif support is now available through the imagecreatefromavif() and imageavif() functions 関数imagecreatefromavif()およびimageavif()が追加されました。 Avifフォーマットが使えるようになります。 WebPより低容量高画質だそうです。 正直いまだにpng使ってる。 hash The following functions have changed signatures, to support an optional $options argument 3関数hash、hash_file、hash_initに第四引数array $options=[]が追加されました。 アルゴリズムに特有のオプションを渡せるようになります。 Added MurmurHash3 with streaming support. ハッシュアルゴリズムMurmurHash3が追加されました。 $h = hash("murmur3f", 'hoge', options: ["seed" => 42]); var_dump($h); // "231990405db0441823f7f90ce310315d" 実装されたのはmurmur3a・murmur3c・murmur3fの3種類です。 MurmurHash3は引数にシード値を渡せるため、第四引数$optionsが必要となりました。 Added xxHash. ハッシュアルゴリズムxxHashが追加されました。 $h = hash("xxh128", 'hoge', options: ["secret"=>"secret値は136バイト以上の長さが必要".str_repeat('a',100)]); var_dump($h); // "d5ace21ffc307b3ae0737e70c0e7525e" 実装されたのはxxh32・xxh64・xxh3・xxh128の4種類です。 引数にシード値もしくはシークレット文字列を渡すことができます。 MySQLi mysqli.local_infile_directory ini setting has been added ini設定mysqli.local_infile_directoryが追加されました。 マニュアルにはLOCAL DATAって書いてあるのですがそんなSQLは無いので、おそらくLOAD DATA LOCALのことだと思います。 LOAD DATA LOCALで読み込み可能なディレクトリを制限します。 Binding in execute has been added to mysqli prepared statements. mysqli_stmt::executeが実行時バインドできるようになりました。 // 何故か今までできなかった $stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)'); $stmt->execute([$id, $name]); // PDOは今までもできた $stmt = $pdo->prepare('INSERT INTO users(id, name) VALUES(?,?)'); $stmt->execute([$id, $name]); PDOと動作を合わせたものとなります。 A new method has been added to mysqli_result called mysqli_fetch_column(). メソッドmysqli_fetch_columnが追加されました。 PDOStatement::fetchColumnに相当するものです。 正直使いどころがわからない。 PDO MySQL The PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY attribute has been added 定数PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORYが追加されました。 mysqli.local_infile_directoryと同じものです。 PDO SQLite SQLite's "file:" DSN syntax is now supported DSN構文fileがサポートされました。 new PDO('sqlite:file:path/to/sqlite.db?mode=ro') 元々はsqlite:path/to/sqlite.db?mode=roってかんじで指定していたはずなので、ファイルを明記できるようになった? Posix POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS. POSIX定数POSIX_RLIMIT_KQUEUES、POSIX_RLIMIT_NPTSが追加されました。 FreeBSDでのみ定義されます。 Standard fputcsv() now accepts a new "eol" argument fputcsv()に第6引数string $eol = "\n"が追加されました。 行末の改行を変更できます。 引数が多すぎるのでarray $optionsにしてほしい。 SPL SplFileObject::fputcsv() now accepts a new "eol" argument SplFileObject::fputcsv()に第5引数string $eol = "\n"が追加されました。 関数fputcsv()と全く同じ変更です。 Changes in SAPI modules CLI コマンドラインの変更点。 Using -a without the readline extension will now result in an error. readline拡張機能が有効でないときは、PHPの対話シェル-aがエラーになるようになりました。 これまでは-aを無視して通常モードのPHPが起動していました。 Remote functionality from phpdbg has been removed phpdbgのリモート機能が削除されました。 とあるのですがなんのことだかわかりません。 -aとかがなくなったってことでいいのかな。 Deprecated Functionality 非推奨になった機能・関数など。 Core . Implementing the Serializable interface without also implementing __serialize() and __unserialize() has been deprecated. Serializableが非推奨になりました。 class HOGE implements Serializable{ public function serialize(){ return serialize($this->data); } public function unserialize($data){ $this->data = unserialize($data); } } // PHP8.1 Deprecated: HOGE implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition // PHP8.0 エラー出ない PHP7.4でマジックメソッド__serialize/__unserializeが実装されたため、今後はそちらが推奨されます。 Implicit conversion of floats to integers that result in loss of precision is deprecated. floatからintへの暗黙の型変換が非推奨になりました。 function toInt(int ...$arg){ } toInt(1.5); // PHP8.1 Deprecated: Implicit conversion from float 1.5 to int loses precision // PHP8.0 エラー出ない 1.5から1へと情報が抜け落ちてしまうためです。 intからfloat等への暗黙の型変換は、情報が抜け落ちないため今後もエラーは出ません。 また、明示的な変換については今後も問題なく可能です。 Calling a static method or accessing a static property directly on a trait is deprecated. traitのstaticプロパティへの直接アクセスが非推奨になりました。 trait T{ public static $foo = 1; } var_dump(T::$foo); // PHP8.1 Deprecated: Accessing static trait property T::$foo is deprecated // PHP8.0 エラー出ない Returning a non-array from __sleep will raise a warning マジックメソッド__sleepが配列以外を返すとE_WARININGが発生するようになりました。 class A{ public function __sleep(){ return 1; } } $a = new A; serialize($a); // PHP8.1 Warning: serialize(): A::__sleep() should return an array // PHP8.0 Warning: serialize(): A::__sleep() should return an array って書いてあるんだけど、実際はPHP8.0でもエラー出ます。 よくわからない。 Returning by reference from a void function is deprecated. 返り値がvoidのメソッド・関数をリファレンスで書くことが非推奨になりました。 function &ref():void{ } // PHP8.1 Deprecated: Returning by reference from a void function is deprecated // PHP8.0 エラー出ない 意味がない文法のため禁止されます。 Automatic conversion of "false" into an empty array on write operands is deprecated. falseから配列の自動生成が非推奨になりました。 $a = false; $a[] = 1; // PHP8.1 Deprecated: Automatic conversion of false to array is deprecated // PHP8.0 エラー出ない 元々voidやundefinedなど存在しないところからは生成可能、intやstring、true等の通常型からは生成不可能でした。 falseはtrueと揃えるべきだろうということで合わせたものとなります。 Ctype Passing a non-string value to ctype_*() functions is deprecated. ctype関数の引数の型において、string型以外は非推奨になりました。 var_dump(ctype_digit(128)); // PHP8.1 Deprecated: ctype_digit(): Argument of type int will be interpreted as string in the future // PHP8.0 false 元々-128から255までのint型をASCII値として扱うというとんでもない罠仕様があったため、これを防ぐついでに意味のない入力を禁止します。 Date The date_sunrise() and date_sunset() functions have been deprecated date_sunriseとdate_sunsetが非推奨になりました。 date_sun_infoが完全上位互換なのでそちらを使いましょう。 The strftime() and gmstrftime() functions have been deprecated strftimeとgmstrftimeが非推奨になりました。 これらはプラットフォームによって出力がかわってしまうためです。 影響を受けないDateTime::format()などを使いましょう。 Filter The FILTER_SANITIZE_STRING and FILTER_SANITIZE_STRIPPED filters have been deprecated. 定数FILTER_SANITIZE_STRING・FILTER_SANITIZE_STRIPPEDが非推奨になりました。 一見strip_tagsと同じように見えて異なる動作であり、何に対するサニタイズなのかも明白にされておらずわかりにくいため削除されます。 The filter.default ini setting is deprecated. ini設定filter.defaultが非推奨になりました。 これは$_REQUEST等の入力値をフィルタリングする機能です。 マジッククォート以上に強力な機能であり、存在そのものが危険であるため封印されます。 GD The $num_points parameter of image(open|filled)polygon has been deprecated. imagepolygonなどの引数$num_pointsが非推奨になりました。 そもそもPHPで絵なんて描かないからわからぬ。 Hash The mhash*() functions are deprecated. mhashをはじめとしたmhash*関数が非推奨になりました。 かわりにhash*関数を使いましょう。 IMAP The NIL constant has been deprecated. 定数NILが非推奨になりました。 NILといえばNULLと同じと思われがちですが、PHPではNILの値は0です。 Intl Calling IntlCalendar::roll() with bool argument is deprecated. IntlCalendar::roll()の第二引数$valueの型boolが非推奨になりました。 trueは1、falseは-1と、他の関数ではありえない使われ方をしていました。 Calling mb_check_encoding() without an argument is deprecated. 引数なしのmb_check_encoding()が非推奨になりました。 実はまともに実装されていませんでした。 MySQLi The mysqli_driver::$driver_version property has been deprecated. mysqli_driver::$driver_versionプロパティが非推奨になりました。 このプロパティは10年以上更新されておらず実質的に意味がありません。 かわりにPHP_VERSION_IDが推奨されています。 Calling mysqli::get_client_info in OO style or passing $mysqli argument to mysqli_get_client_info() function has been deprecated. mysqli::get_client_infoの引数が非推奨になりました。 引数なしのmysqli_get_client_info()はクライアントのバージョンを返します。 The mysqli::init() method has been deprecated. mysqli::initが非推奨になりました。 これは生成メソッドなのに何故かクラスメソッドではなくインスタンスメソッドであり、使い道がわからない代物でした。 OCI8 The INI directive oci8.old_oci_close_semantics has been deprecated. ini設定oci8.old_oci_close_semanticsが非推奨になりました。 この設定はだいぶ昔に後方互換性だけのために導入されたものなので、そろそろ不要です。 ODBC odbc_result_all() has been deprecated. 関数odbc_result_all()が非推奨になりました。 取得した結果をいきなりHTMLテーブルに入れて表示する、しかもHTMLエスケープしない、という意味のわからない関数です。 PDO The PDO::FETCH_SERIALIZE mode has been deprecated. 定数PDO::FETCH_SERIALIZEが非推奨になりました。 これは内部的にSerializableインターフェイスを使っていたため、Serializableと共にこちらも非推奨になります。 しかしそれ以前に、実はそもそも動いていなかったとかなんとかいう話があるっぽいですが。 PgSQL Not passing the connection argument to PgSQL functions and using the default connection is deprecated. pg_query()など一部のPgSQL関数を、引数$connectionを渡さずに呼び出すことが非推奨になりました。 コネクションを渡しましょう。 SOAP The ssl_method option for the SoapClient constructor has been deprecated SoapClient::__construct()のオプションssl_methodが非推奨になりました。 かわりにcontextオプションを使いましょう。 Standard Calling key(), current(), next(), prev(), reset(), or end() on objects is deprecated. オブジェクトに対する配列ポインタ操作関数の使用が非推奨になりました。 詳しくは配列ポインタ操作関数はIteratorを無視するに書きましたが、かなり不安な挙動であるため禁止されます。 The strptime() function has been deprecated. 関数strptime()が非推奨になりました。 この関数はプラットフォームやロケールに影響を受けてしまうためです。 影響を受けないDateTime::createFromFormat()などを使いましょう。 The auto_detect_line_endings ini setting has been deprecated. ini設定oci8.old_oci_close_semanticsが非推奨になりました。 古いMacと互換するためだけの機能なので、もはや不要です。 The FILE_BINARY and FILE_TEXT constants are deprecated. 定数FILE_BINARYとFILE_TEXTが非推奨になりました。 これらは定義されていただけで、何の効果もありませんでした。 Changed Functions 動作に変更のあった関数。 Core Properties order used in foreach, var_dump(), serialize(), object comparison etc. was changed. 各関数やループにおいて、オブジェクトのプロパティ出力の順序が規定・文書化されました。 親クラス→子クラスの順番です。 これまでは順序が規定されておらず、実装に依存する状態でした。 Filter The FILTER_FLAG_ALLOW_OCTAL flag of the FILTER_VALIDATE_INT filter now accept octal string with the leading octal prefix ("0o"/"0O") フィルタフラグFILTER_FLAG_ALLOW_OCTALが、"0o123"のような値を受け入れるようになりました。 8進数表記として"0o123"ができるようになったので、そのための変更です。 GMP All GMP function now accept octal string with the leading octal prefix ("0o"/"0O") 全てのGMP関数が、"0o123"のような値を受け入れるようになりました。 8進数表記として"0o123"ができるようになったので、そのための変更です。 gmp_init('0o123'); // PHP8.1 エラー出ない // PHP8.0 Fatal error: Uncaught TypeError: gmp_init(): Argument #1 ($num) is not an integer string PDO ODBC PDO::getAttributes() with PDO::ATTR_SERVER_INFO and PDO::ATTR_SERVER_VERSION now return values instead of throwing PDOException. PDO::getAttribute()へ引数PDO::ATTR_SERVER_INFOやPDO::ATTR_SERVER_VERSIONを渡すと、エラーを出すかわりに値を返すようになりました。 ODBCだけなので、PDO_MySQL等はこれまでも問題なく値を取得できていました。 Reflection ReflectionProperty::setAccessible() and ReflectionMethod::setAccessible() no longer have an effect. ReflectionProperty::setAccessible()とReflectionMethod::setAccessible()が、何の効果も持たなくなりました。 privateなプロパティにも、リフレクション経由であれば即アクセスできるようになります。 class HOGE{ private static $foo = 'bar'; } var_dump((new ReflectionProperty(HOGE::class, 'foo'))->getValue()); // PHP8.1 bar // PHP8.0 Fatal error: Uncaught ReflectionException: Cannot access non-public property どうせ毎回setAccessible(true)するんだから最初からデフォルトでいいだろ、という判断です。 Standard syslog() is now binary safe. 関数syslog()がバイナリセーフになりました。 New Functions 新しい関数。 Core array_is_list(array $array) 関数array_is_list()が追加されました。 0始まりでキーの抜けがない配列である場合のみtrueになります。 array_is_list([0=>1, 1=>2]); // true array_is_list([0=>1, 2=>2]); // false 他言語で言うところの配列であるかを区別できます。 pcntl Added pcntl_rfork for FreeBSD variants FreeBSD向けに関数pcntl_rfork()が追加されました。 pcntl_fork()と何がちがうのかはよくわかりません。 Reflection Added ReflectionFunctionAbstract::getClosureUsedVariables メソッドReflectionFunctionAbstract::getClosureUsedVariables()が追加されました。 無名関数に渡された変数を取り出すことができます。 $foo = 1; $function = function () use ($foo) { }; $reflector = new ReflectionFunction($function); var_dump($reflector->getClosureUsedVariables()); // ["foo"=>1] どんなときに使うんだこれ。 Standard Added fsync() and fdatasync() 関数fsync()およびfdatasyncが追加されました。 C言語のfsync・fdatasyncのラッパーのようです。 Sodium Added the XChaCha20 stream cipher interface functions 関数sodium_crypto_stream_xchacha20・sodium_crypto_stream_xchacha20_keygen・sodium_crypto_stream_xchacha20_xorが追加されました。 libsodiumがXChaCha20に対応したので、Sodiumライブラリが追随したようです。 Added the Ristretto255 functions 関数sodium_crypto_core_ristretto255_add()・sodium_crypto_core_ristretto255_from_hash()・sodium_crypto_core_ristretto255_is_valid_point()・sodium_crypto_core_ristretto255_random()・sodium_crypto_core_ristretto255_scalar_add()・sodium_crypto_core_ristretto255_scalar_complement()・sodium_crypto_core_ristretto255_scalar_invert()・sodium_crypto_core_ristretto255_scalar_mul()・sodium_crypto_core_ristretto255_scalar_negate()・sodium_crypto_core_ristretto255_scalar_random()・sodium_crypto_core_ristretto255_scalar_reduce()・sodium_crypto_core_ristretto255_scalar_sub()・sodium_crypto_core_ristretto255_sub()・sodium_crypto_scalarmult_ristretto255()・sodium_crypto_scalarmult_ristretto255_base()が追加されました。 libsodiumがRistrettoに対応したので、Sodiumライブラリが追随したようです。 New Classes and Interfaces 新しいクラス・インターフェイス。 Intl Added IntlDatePatternGenerator クラスIntlDatePatternGeneratorが追加されました。 Intlのそれのラッパーです。 $skeleton = 'yyyyMMddHmmss'; (new \IntlDatePatternGenerator('ja_JP'))->getBestPattern($skeleton); // "yyyy/MM/dd H:mm:ss" (new \IntlDatePatternGenerator('en_US'))->getBestPattern($skeleton); // "MM/dd/yyyy, HH:mm:ss" (new \IntlDatePatternGenerator('pt_BR'))->getBestPattern($skeleton); // "dd/MM/yyyy HH:mm:ss" (new \IntlDatePatternGenerator('de_DE'))->getBestPattern($skeleton); // "dd.MM.yyyy, HH:mm:ss" 各国の日時形式に合った感じのフォーマットにしてくれるので国際化対応がやりやすくなります。 ただ渡せるフォーマットがdateのやつじゃなくてICUのフォーマットなのでめんどくさい。 Removed Extensions and SAPIs 削除されたエクステンション・SAPIは無し。 Other Changes to Extensions その他の変更点。 GD imagewebp() can do lossless WebP encoding by passing IMG_WEBP_LOSSLESS as quality. 関数imagewebp()は、引数qualityに定数IMG_WEBP_LOSSLESSを渡すとロスレス圧縮できるようになりました。 Mbstring Unicode data tables have been updated to Unicode 14. UnicodeテーブルがUnicode 14に更新されました。 MySQLi The mysqli_stmt::next_result() and mysqli::fetch_all() methods are now available when linking against libmysqlclient. libmysqlclientを使っている場合でも、 mysqli_stmt::next_resultとmysqli_result::fetch_all が使えるようになりました。 まあ余程の理由でもないかぎりmysqlndを使いましょう。 OpenSSL The OpenSSL extension now requires at least OpenSSL version 1.0.2. OpenSSLエクステンションが要求するOpenSSLライブラリの最低バージョンが1.0.2になりました。 これまでは、PHP7.0以降OpenSSL0.9.8以上、PHP7.1以降OpenSSL1.0.1以上でした。 OpenSSL 3.0 is now supported. OpenSSL3.0がサポートされました。 デフォルトではレガシーな暗号化形式の多くが無効化されているようです。 Phar Use SHA256 by default for signature. pharアーカイブのシグネチャのデフォルトがSHA256になりました。 これまではSHA1でした。 Add support for OpenSSL_SHA256 and OpenSSL_SHA512 signature. pharアーカイブのシグネチャがOpenSSL_SHA256とOpenSSL_SHA512をサポートしました。 Phar::setSignatureAlgorithmで設定可能です。 SNMP add SHA256 and SHA512 for security protocol. SNMPがSHA256とSHA512をサポートしました。 SNMP::setSecurityで設定可能です。 Standard --with-password-argon2 now uses pkg-config to detect libargon2. コンパイルオプション-with-password-argon2は、libargon2の場所を環境変数PKG_CONFIG_PATHではなくpkg-configを使って探すようになりました。 Windowsには関係ないのでよくわかりません。 --with-external-libcrypt now allows to use system libcrypt/libxcrypt instead in PHP own implementation. コンパイルオプション--with-external-libcryptを指定すると、システムに入っているlibcrypt/libxcryptを使用します。 未指定の場合は、これまでどおりPHPに組み込まれている暗号化処理を使用します。 Windowsには関係ないのでよくわかりません。 New Global Constants グローバル定数。 MySQLi MYSQLI_REFRESH_REPLICA has been added as a replacement for MYSQLI_REFRESH_SLAVE 定数MYSQLI_REFRESH_REPLICAが追加されました。 値はMYSQLI_REFRESH_SLAVEと同じです。 そしてMYSQLI_REFRESH_SLAVEは将来のバージョンで削除されます。 ポリがコレでなんちゃらのアレです。 Sockets The following socket options are now defined 定数SO_ACCEPTFILTER / SO_DONTTRUNC / SO_WANTMORE / SO_MARK / TCP_DEFER_ACCEPTが追加されました。 BSDソケットのラッパーのようです。 Changes to INI File Handling iniファイルの変更点。 The log_errors_max_len ini setting has been removed. ini設定log_errors_max_lenが削除されました。 実はPHP8.0以降効果がなかったんだよとか言ってるんだけど、これまでそんな話出てきてたっけ? A leading dollar in a quoted string can now be escaped. 二重引用符で囲まれた先頭の$をエスケープできるようになりました。 すなわち"\${"は"${"と解釈されます。 とか書いてあるんだけど、これずっと前からそうなってるんですよね。 いったい何を言いたいのかよくわからない。 Backslashes in double quoted strings are now more consistently treated as escape characters. 二重引用符で囲まれた文字列のエスケープの扱い方がより一貫的になりました。 例として、"foo\\"の後ろに改行以外の文字があったときの動作が変わります。 とか書いてあるんだけど、これも前から同じなんですよね。 例が悪いのか何なのかわからない。 Windows Support Windowsのサポートに変更はありません。 即ち、これまでどおり使い続けることができます。 Performance Improvements UPGRADINGには何故か何も書かれていないのですが、ランディングページにパフォーマンスの改善点が記載されています。 ・ARM64(AArch64)へのJITバックエンド対応。 ・リクエスト毎にクラスを再リンクせず、キャッシュを継続する。 ・クラス名の解決の高速化。 ・timelibおよびext/dateの高速化。 ・SPLイテレータの改良。 ・serialize/unserializeの最適化。 ・いくつかの内部関数(get_declared_classes()・explode()・strtr()・strnatcmp()・dechex()等)の最適化。 ・JITの改善。 JITの無い状態でもSymfonyが23%高速化、WordPressが3.5%高速化されています。 Symfonyが高速化されたということは、Laravelも高速化されるということです。 ……いや23%って何だよ。 いくらなんでもおかしくないか??? 感想 PHP8.1で目立つのは、型に関する機能の追加、そしてレガシーの排除です。 列挙型に交差型にnever型に新潟アクセス修飾子にその他諸々と、型の表現方法が大幅に拡充されました。 なんか書いたらなんとなく動くというインターネット黎明期から引き継がれてきた大らかさはますます狭まり、きっかりかっちり型を縛ったstrictプログラミングがPHPでもほぼ主流となっています。 まあ、当時のように多少ゆるふわでもなあなあでどうにかなる時代はとうに過ぎ去り、ほんの少しでも穴があったら事業存続に繋がる損失になるレベルまでインターネットの領域が広まってきたので、これは仕方のない方向性であると言えるでしょう。 そしてFiberはいまだ未知数ですが、もしかしたら今後のPHPのパラダイムが転換するほどの機能になるかもしれません。 何も起こらないかもしれません。 そしてどんどん新機能が追加され続けているにもかかわらず、何故か高速化も相変わらず進んでいます。 ふしぎですね。 今回はE_DEPRECATEDの追加が目立ちますが、それ以外でいきなり動かなくなるって事態はほぼ無いはずなので、PHP8.0で動いているコードなら概ねそのままいけると思います。 とはいえ初物に飛びつくのは危ないので、PHP8.1.3くらいになったら移行を検討してみてはいかがでしょうか。 これからのPHPは、Nikitaの離脱という痛手こそあったものの、同時にPHP財団が設立され、大きな節目を迎えました。 この試みがうまくいけば、今後もPHPはきっと進化し続けることでしょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む