Skip to content

PHP式プログラミング入門

公開日:

にオンラインのZoom会議で開催された『第二回関数型プログラミング(仮)の会』でライトニングトーク(5分)として発表しました。

Download PDFPDF

スライドテキスト

Page 1

PHP式プログラミング入門

Guide to expression-oriented programming in PHP

USAMI Kenta

2022.01.21

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 仕事ではPHPという静的型付き関数型プログラミング言語を書いています
  • 趣味ではEmacs Lispという雑草のような生命力*の言語を書いています

(*出典: 『初めての人のためのLISP』)

Page 3

普段はEmacsというLisp専用OSでPHP開発する環境を作ってます

Page 4

こういうバックグラウンドなので関数型よくわからない…

Page 5

map/reduceが関数プログラミングなんでしょ

Page 6

僕はあらゆるループをLispのLOOPマクロで書きたい派なんで…

Page 7

ちなみにLispはElixirと同様に、基本的にreturnを書けません

Page 8

さて

Page 9

PHPってどういう言語

Page 10

PHPはHTMLに書く言語?

<!DOCTYPE html public>

<p>現在は<?= date('%H時%i分%s秒です') ?></p>

Page 11

PHPスクリプト

<?php echo "<!DOCTYPE html public>\n\n";echo "<p>現在は", date('%H時%i分%s秒です'), "</p>\n";

Page 12

こういうノリでWebアプリがサクっと書ける素朴な言語

Page 13

PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

Page 14

PHPとクロージャ

  • 基本的にレキシカルスコープです

Page 15

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数

Page 16

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数
  • 外側の変数をキャプチャするには明示が必要

function ($a, $b) use ($c) { return $a + $b + $c; }

Page 17

PHPとクロージャ

  • 基本的にレキシカルスコープです
  • function ($a, $b) { return $a + $b; } のような無名関数
  • 外側の変数をキャプチャするには明示が必要

function ($a, $b) use ($c) { return $a + $b + $c; }

  • PHP 7.4からは fn($a, $b) => $a + $b + $c;
  • 明示しなくても キャプチャできて便利

Page 18

これだけ知ればおもしろいこといろいろできそう

Page 19

ところで

Page 20

世の中にはいろんな制約を課したプログラミングがある

Page 21

セミコロンなしでJavaを書くとか

Page 22

Pythonワンライナーとか

Page 23

$なしでPHPを書くとか

Page 24

https://tadsan.fanbox.cc/posts/329540

Page 25

これはこれでおもしろい

Page 26

(再掲)PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

Page 27

(再掲)PHPはこんな言語

  • 汎用プログラミング言語 (Webだけではない)
  • 昨今ではHTMLにそのまま埋め込むよりもクラス定義が主体
  • <?php タグの内側のシンタックスはCっぽい
  • C言語っぽい {} を使った制御構造がある
  • 式文が ; で終端する

こいつら目障りじゃないですか?

Page 28

セミコロンレス

Javaでは

Page 29

https://horosora.hatenablog.com/entry/2018/08/03/162147より引用

Page 30

; だけじゃなくて{} も縛りたくない?

Page 31

今回の本題

Page 32

(再掲)PHPはHTMLに書く言語

<!DOCTYPE html public>

<p>現在は<?= date('%H時%i分%s秒です') ?></p>

?> 直前は; を削れる

Page 33

すべての処理を<?= に押し込む

Page 34

できれば一個の<?= に押し込む

Page 35

PHPは式指向プログラミングできる下地はいろいろある

Page 36

PHPの特徴

  • スクリプト言語にありがちな定義せずに代入したら使える変数
  • 代入は式!
  • C言語とほぼ同じ制御構造なので if や while は {} または ; 必須
  • 分岐は条件演算子 $cond ? $then : $else でどうにか
  • ループは array_map(), array_reduce() でどうにか

Page 37

これだけできればチューリング完全であることは自明

Page 38

FizzBuzzを書いてみよう

1から100を改行区切りで出力

<?= implode(range(1, 100), "\n") ?>

Page 39

FizzBuzzを書いてみよう

1から100をFizzBuzzに変換して改行区切りで出力

<?= implode(array_map(fn(int $n): string => [[$n, 'Buzz'],['Fizz', 'FizzBuzz']][$n%3==0][$n%5==0],range(1, 100), "\n") ?>

Page 40

こういうノリでmap/reduceに変形できれば任意の処理が可能

Page 41

パイプライン演算子が欲しくなってくるぜ(Lispならスレッドマクロがあるのに)

Page 42

これはLispですね

Page 43

そう思ったことが私にもありました

Page 44

ある日のこと…

Page 45

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

Page 46

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

Page 47

これはやばい

Page 48

https://qiita.com/perpouh/items/807775de16986a956d1c より引用

文を多用してるのでfn() に置き換え困難

Page 49

この路線の限界

Page 50

array_map/array_reduceはあくまで配列処理

Page 51

無限ループできない

Page 52

旧式のfunctionでは自己再帰可能

変数を参照としてキャプチャしないと

<?php

いけない

$fib = function (int $n) use (&$fib) {return ($n < 2)? 1: $fib($n - 1) + $fib($n -2);};

Page 53

アロー関数(fn)では自己再帰不能

クロージャ作成時にはクロージャ自体は作られてない

<?php

ので束縛できない

$fib = fn (int $n) =>($n < 2)? 1: $fib($n - 1) + $fib($n -2);

Page 54

じゃあどうすればいい

Page 55

そうですね

Page 56

不動点演算子

Page 57

いわゆるYコンビネータ(Zコンビネータ)

Page 58

Zコンビネータ

Page 59

これで勝てる

Page 60

可読性重視版

Page 61

圧縮版

Page 62

完

Page 63

まとめ

Page 64

PHPはLispじゃない式指向プログラミングは大変

Page 65

エクストリームスポーツを楽しもう

Page 66

ご静聴ありがとうございました

Page 67

あとPHPでもかなり実用的な静的型検査ができるようになってる

Page 68

関連記事

  • PHP式プログラミング入門 (原稿版)
  • PHPの無名関数式とは何か、そしてPHP7.4のアロー関数にそなえよう
  • Functoolsを作った
  • Functoolsで過剰にスマートなPHPを書こう (無名再帰篇)