
執筆者
M.N.
PHPの関数

PHPカンファレンス2025の振り返り、第2回です。
前回の記事では「PHPの今とこれから2025」について書きましたが、今回は当日聴講した中で個人的に一番刺さったセッション「純粋 vs 副作用 〜 PHPはなぜ難しいのか?」について振り返ります。
正直に言うと、当時「副作用」という言葉自体、用語としてちゃんと認識していませんでした。
普段なんとなく使い分けていた感覚に、ちゃんと名前と理屈がついた、という感じのセッションでした。
純粋な関数とは何か
セッションの出発点は、数学的な関数の話でした。
数学の関数は、いつどこで実行しても結果が同じになります。f(x) = x + 1 であれば、x に2を入れれば常に3が返ってくる。
これは当たり前のことですが、改めて言われると「たしかに」と思いました。
PHPの関数も、こういう「数学っぽい関数」として書くことができます。
同じ引数を渡したとき、呼び出し結果が必ず同じになる関数です。
こうした関数は、戻り値を受け取らないと意味がありません。
数学っぽくない関数、つまり「副作用」を持つ関数
一方で、
PHPの関数には「何かに影響を及ぼす」タイプの関数もあります。
画面に出力する、ファイルに書き込む、DBを更新する……といった関数です。
これらは戻り値を受け取らなくても意味があります。
むしろ「何かに影響を与えること」自体が目的になっています。
セッションでは、PHPの関数の「罠」として、以下のようなパターンが紹介されていました。
◆呼び出すごとに結果が変わる(かも):日時関数、ランダム関数など
◆呼び出すごとにどこかに影響を及ぼす(かも):var_dump(), header(), ob_start()など
◆両方を兼ね備える:DB・ファイルシステム関数・外部通信
これを聞いて、「あれもこれも副作用を持つ関数だったのか」と、自分が普段書いているコードを思い返してちょっとぞわっとしました。
PHPでのテスト

テストしにくさの正体
このセッションで一番「なるほど」と思ったのが、「テストしにくさの正体」の説明でした。
テストしにくいコードには、大きく2つの側面があるという話です。
結果が予想しにくい
外部の状態の影響を受けるコードは、テスト対象を実行した結果がそもそも予想しにくくなります。
影響を受ける対象が多すぎて、全部を把握できない状態になりがちです。
結果に何が起こるか制御できない
ファイルに書き込まれる、DBが更新される……といった「副作用」がある場合、その結果を制御するのが難しくなります。
セッションでは、こうした「制御できないもの」は「制御できるもの」にブレークダウンすればいい、というシンプルな指針が示されていました。
言われてみれば当然なのですが、自分の中で意識的に整理したことがなかったので、すっと入ってきました。
副作用を切り離す、というアプローチ
「任意の処理を純粋関数で書く」ということ自体は「できない」とセッションでは明言されていました。
アプリケーションには必ずDBアクセスや外部通信など、副作用を持つ処理が必要になるからです。
ただ、
それらに依存する部分を抽象化して切り離すことで、テスト時にシンプルな偽物(モックやスタブ)に差し替えてテストできるようになる、という話がありました。
ここで「DIは純粋関数型になれないオブジェクト指向言語の武器」というフレーズが出てきたのですが、これが個人的に一番刺さった一言でした。
DI(依存性注入)は普段から「テストしやすくするためのもの」というざっくりした理解で使っていましたが、「純粋関数型になれない言語が、副作用を扱うための工夫」という位置づけで説明されると、急に腑に落ちる感じがありました。
プログラムで制御しやすい単位とは

セッションのまとめとして、「プログラムで制御しやすい単位」として純粋関数の特徴が挙げられていました。
・参照透過性(同じ入力には常に同じ出力)
・副作用を持たない
この2つを満たす部分が大きいほど、テストが書きやすく、挙動が予測しやすいコードになる、ということです。
PHPStanによる純粋性の判定
余談的な話として、PHPStanが関数の純粋性をどう判定しているか、という話もありました。
01 ImpurePoints
02 functionMetadata.hasSideEffects
03 PHPDocの@pureタグ
といった仕組みがあるそうです。
静的解析の文脈でも「純粋かどうか」が一つの軸として扱われているというのは、この概念が単なる理論ではなく、実際のツールにも組み込まれている考え方なんだな、と感じました。
また、
「純粋じゃなくても戻り値が重要な関数もある」という話もあり、これは前回の記事で触れたNoDiscardアトリビュート(PHP8.5で追加)にもつながる話だと、振り返ってみて気づきました。
戻り値を無視してはいけない関数、という観点は、このセッションとも地続きだったわけです。
振り返ってみての所感
当日のメモには「関数の『副作用』という概念について気にしたことがなかった」と書いていました。
値を返すだけの純粋関数と、その他に影響を及ぼす関数を分けて考えるべきだ、という話は、当時もしっくりきていたようです。1年経って読み返してみても、この考え方は今も自分のコードを見直すときの軸になっている気がします。
特に「DIは純粋関数型になれないオブジェクト指向言語の武器」という一言は、今でもときどき思い出します。
新しく書くコードで「この処理、DIで切り離せるかな」と考えるとき、頭の片隅にこのフレーズがある感じです。
次回は、「PHPで作るTCP/IPプロトコル」についてレポートしたいと思います。













