Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
夢の無限スパゲッティ製造機 #phperkaigi
Search
hideki kinjyo
PRO
March 22, 2026
Technology
470
0
Share
夢の無限スパゲッティ製造機 #phperkaigi
https://fortee.jp/phperkaigi-2026/proposal/40eed9f2-69a1-4b38-8301-bcf21e902eb7
の発表資料です
hideki kinjyo
PRO
March 22, 2026
More Decks by hideki kinjyo
See All by hideki kinjyo
ソースコード→AST→オペコード、の旅を覗いてみる
o0h
PRO
1
130
PCOVから学ぶコードカバレッジ #phpcon_odawara
o0h
PRO
0
340
夢の無限スパゲッティ製造機 -実装篇- #phpstudy
o0h
PRO
0
230
PHPer Book Revue 「雑に作る」 #phperkaigi
o0h
PRO
0
350
俺にも私がAIと作った オススメの個人ツールを語らせてくれ
o0h
PRO
0
59
#phperbiglt のLT
o0h
PRO
0
94
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
270
symfony/mcp-bundleで、既存アプリケーションもお手軽にMCPサーバー化
o0h
PRO
1
160
組織もソフトウェアも難しく考えない、もっとシンプルな考え方で設計する #phpconfuk
o0h
PRO
10
5.9k
Other Decks in Technology
See All in Technology
Terragrunt x Snowflake + dbt で作るマルチテナントなデータ基盤構築プラットフォーム
gak_t12
0
250
GCASアップデート(202603-202605)
techniczna
0
200
Oracle Cloud Infrastructure presents managed, serverless MCP Servers for Oracle AI Database
thatjeffsmith
1
350
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
4.5k
AWS運用におけるAI Agent活用術 / JAWS-UG 神戸 #11 LT大会
genda
1
280
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
6
1.4k
みんなの考えた最強のデータ基盤アーキテクチャ'26前期〜前夜祭〜ルーキーズ_資料_遠藤な
endonanana
0
430
鹿野さんに聞く!CSSの最新トレンド Ver.2026
tonkotsuboy_com
6
3.5k
パーソルキャリア IT/テクノロジー職向け 会社紹介資料|Company Introduction Deck
techtekt
PRO
0
200
SLI/SLO、「完全に理解した」から「チョットデキル」へ
maruloop
5
550
サイボウズ、プラットフォームエンジニアリング始めるってよ ― プラットフォームチームの事業貢献と組織アラインメントの強化
ueokande
0
120
SpeechTranscriber + AIによる文字起こし機能
kazuki1220
0
110
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
The Cult of Friendly URLs
andyhume
79
6.9k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.2k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.9k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
140
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.2k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
330
The Limits of Empathy - UXLibs8
cassininazir
1
330
Test your architecture with Archunit
thirion
1
2.2k
BBQ
matthewcrist
89
10k
Paper Plane
katiecoart
PRO
1
50k
Ruling the World: When Life Gets Gamed
codingconduct
0
230
Transcript
夢の無限スパゲッティ製造機 PHPerKaigi 2026 Hideki Kinjyo GitHub: o0h / X: @o0h_
[発表用] v1.0.0
夢の無限スパゲッティ製造機 #phperkaigi.2026 Hideki Kinjyo GitHub:o0h / X:@o0h_
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a こんにちは〜〜! 3
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 身近な相手が不意に見せた 普段と違う一面 って、どうですか? 4
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a PHPで言うとgoto どうですか? 5
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 6 昨年の発表
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 7 いち場面
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 8 いち場面
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 9 いち場面
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a それから1年 (One year later)
10
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 11 私 スパゲティをやっている人、 増えたのかな?
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 12 私 どきどき わくわく
質問コーナー 最近、「GOTO使ったよ」って人 どのくらい居ますか?🙋 13 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 14 私 使えないなら 使えるようにしないと!!
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 15 私 夢の無限スパゲッティ製造機だ!
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 16 私 夢の無限スパゲッティ製造機だ!
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a DEMO 17
自己紹介 • 金城秀樹 / きんじょうひでき • GitHub: @o0h / 𝕏
: @o0h_ • 好きなスパゲッティはカルボナーラ • アイコンは美味しい鮭親子丼のChef ver.です • 最近はPodcastをやっています • ハッシュタグ: #readlinefm 18 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
おしながき 1. スパゲッティの世界と製造機の挑戦 2. 実演・基本的な処理 3. 実演・入り組んだ処理 4. 限界、そして言語の壁 5.
最後に言いたいこと 19 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
1. スパゲッティの世界と製造機の挑戦 2. 実演・基本的な処理 3. 実演・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 「スパゲッティ」序説
スパゲッティ? 22 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a https://japan.zdnet.com/glossary/exp/スパゲッティコード/
スパゲッティ? 23 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a https://japan.zdnet.com/glossary/exp/スパゲッティコード/
現代のプログラミングのパワー 24 スパゲッティつらい 節操ないgoto辛い 構造化プログラミング • 今より言語もハードも未成熟の時代、 「ジャンプ命令」でのロジック整理 • 複雑化・大規模化するにつれ、
読解や保守の「キャパオーバー」 • 「構造化」でロジックを整理しやすく • for文やif文、function そして現代へ─ スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a GO TO文こそ,皿盛りのスパゲッティにおけるスパ ゲッティ, ネズミの巣におけるボロクズ,
つまり 原材料であるわけだ。いっそ GOTO 文がなかった ら, さぞいいだろう, とつい考えたくなる 25 ─ bit 1975年05月号(通巻75号) 共立出版 P367
逆に言えば・・・ 26 スパゲッティつらい 節操ないgoto辛い 構造化プログラミング ここの山をとびこえろ!!!! そして現代へ─ スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a
逆に言えば・・・ 27 スパゲッティつらい 節操ないgoto辛い 構造化プログラミング ここの山をとびこえろ!!!! そして現代へ─ 昨今すっかり味わいにくくなった スパゲッティへの回帰 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a gotoの文法・使い方について まず始めに
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 見たことない・触ったことない人向けに PHPにおける「goto」の文法を おさらいします 29
基礎文法 • gotoによって、指定された 場所までジャンプができる • ジャンプ先は「ラベル」を 指定する 30 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B;
基礎文法 • gotoによって、指定された 場所までジャンプができる 31 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi
#a <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; ラベル = 「文字列+コロン」 A: B: C:
基礎文法 32 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto
C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; ジャンプ = 「goto+ラベル+セミコロン」 goto A; goto B;
基礎文法 33 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto
C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; 最初にCにジャンプして
基礎文法 34 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto
C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; C → Bに
基礎文法 35 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto
C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; B → A
基礎文法 <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo
"BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; Cに来たよ Bに来たよ Aに来たよ 36 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B;
<?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n";
goto A; C: echo "CʹདྷͨΑ\n"; goto B; 基礎文法 <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; • ラベルは「ジャンプ先」に 指定ができるが、外からの 進入を防ぐものではない 37 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a <?php goto C; A: echo "AʹདྷͨΑ\n"; exit(); B: echo "BʹདྷͨΑ\n"; goto A; C: echo "CʹདྷͨΑ\n"; goto B; A → B → A → ・・・ と無限ループに陥るので、 Aの内側で離脱処理(exitなど)を 呼ぶ必要がある
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a これを使いこなして 良い感じにやっていくぞ! 38
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a スパゲッティの定義
スパゲッティの定義(1/2) このセッションでは、「縛りあり」のプログラミングをしていきます • ざっくり言うと、 「反復・分岐等の制御構文や関数定義の禁止」 「オブジェクト指向的な記述の禁止」 の2つ • その実現のために、ふんだんにgotoを使っていくことに 40
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スパゲッティの定義(2/2) • 条件分岐が「完全に無し」だとロジックが書けないので、 「goto命令だけを含むif」は許容する 45 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi
#a if ($me !== 'taro') goto taro_igai;
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a ◯ ✕
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a いかにして夢を叶えるか? 〜無限スパゲッティ製造機のアプローチ〜
どんなプログラムも根っこは単純 • 高級言語で書かれたコードは、そのまま実行されるわけではない • 掘り下げていけば、低水準な「機械語」まで落とし込まれる • その世界では「オブジェクト指向」も「ループ文」も無いハズだ!! 48 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
どんなプログラムも根っこは単純 • 高級言語で書かれたコードは、そのまま実行されるわけではない • 掘り下げていけば、低水準な「機械語」まで落とし込まれる • その世界では「オブジェクト指向」も「ループ文」も無いハズだ!! 49 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 下に降りればスパゲッティが生えていそう
<?php $tmp0 = … sub: ————— goto hoge; end: アプローチ
1. PHPで書かれたソースコードをインプットとして 2. いったんオペコードに変換し 3. 再びPHPの表現に戻す! 50 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a ソースコード オペコード <?php function hoge($x) { ————— } 0 INIT_FCALL 'hoge' 1 SEND_VAL 1 2 SEND_VAL 10 3 DO_ICALL $0 4 ECHO $0 5 RETURN 1 オペコード スパゲッティ
工程1: ソースコード • プログラマーのための表現 • 色々な抽象化/構造化が利用可能 • (説明不要ですね!) 51 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
工程2: オペコード • VM(仮想マシン)のための表現 • やや抽象化は残るものの、素朴で限定された命令で作られる • 制御フローは、人間よりもCPU(機械)によった形に • ifやforが無くなる!
• 代わりに、「ジャンプ命令」 に書き換えらえる 52 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
• 基本的に上から実行される • 1行 = 1ステップ <補足> オペコードってどんなもの? 53 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
• 各行は、インデックス・命令・引数の3つのパーツで構成される • 引数の数は命令によって異なる <補足> オペコードってどんなもの? 54 命令(オペコード) 引数(オペランド) インデックス(番号)
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
• 「CV0にtrueを代入する」 <補足> オペコードってどんなもの? 55 boolのtrue ローカル変数 (CV0 = $iikanji)
ASSIGN: 引数1に引数2を代入する スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
• 「CV0をチェックして、値が `0` だったら、3行目にジャンプする」 <補足> オペコードってどんなもの? 56 JMPZ: 引数1がゼロだったら、 引数2の番号にジャンプする
ローカル変数 (CV0 = $iikanji) 番号3 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
工程3: スパゲッティ • オレ達のための表現 • 制御フローは、オペコードをベースにした形に 57 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a 👍
1. スパゲッティの世界と製造機の挑戦 2. 実演・基本的な処理 3. 実演・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
done!
1. スパゲッティの世界と製造機の挑戦 2. 実演・基本的な処理 3. 実演・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a ここからは スパゲッティの アラカルト 60
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a while
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 最初に条件の判定に飛んで
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 条件式の処理を行い
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 条件のチェックと、 ジャンプの実行(→反復処理)
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 再び条件式の判定に ループの中身を実行して
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 満たさなかったら次の行へ
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a for
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
done!
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a function
初めてのfunction 関数をスパゲッティにするために、次の挙動を再現する必要がある 1. 呼び出した場所へ戻れる 2. 1つの値を呼び出し元に返せる 3. 関数の中から関数を呼び出せる 4. ローカルな変数を扱える
77 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
初めてのfunction① 関数をスパゲッティにするために、次の挙動を再現する必要がある 1. 呼び出した場所へ戻れる 2. 1つの値を呼び出し元に返せる 3. 関数の中から関数を呼び出せる 4. ローカルな変数を扱える
78 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
帰りたい コレ、どうしますか? 79 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a today();
echo 'end!!'; function today() { echo date('Y-m-d'); }
帰りたい 80 goto today; echo 'end!!'; exit(); today: echo date('Y-m-d');
関数を ひとかたまりの手続きに 名前をつけて呼び出すもの と捉える 関数(名)に対応する ラベルを作ってジャンプ? スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
関数(名)に対応する ラベルを作ってジャンプ? 帰りたい 81 goto today; echo 'end!!'; exit(); today:
echo date('Y-m-d'); これだと 元の位置に戻ってこれない ここに処理が来ない ✕ そのまま次の行へ スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
帰りたい 82 goto today; return_1: echo 'endʂ'; exit(); today: echo
date('Y-m-d'); goto return_1; 関数呼び出し後に 復帰する位置を設定し、 関数処理の最後にジャンプ スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
帰りたい 83 today(); echo '---'; today(); echo 'endʂ'; 関数が 2回呼び出される時は?
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
帰りたい 84 goto today; return_1: echo '---'; goto today; return_2:
echo 'endʂ'; today: echo date('Y-m-d'); goto return_1; 関数が 2回呼び出される時は? さっきと同じく 復帰する位置を設定して ジャンプ? スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
さっきと同じく 復帰する位置を設定して ジャンプ? 帰りたい 85 goto today; return_1: echo '---';
goto today; return_2: echo 'endʂ'; today: echo date('Y-m-d'); goto return_1; ここに処理が来ない ✕ 戻り先を決め打ちだと 対応できない!! スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
PHPのgotoは綺麗なgoto① • 飛び先のラベルは静的にしか指定できない 86 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
PHPのgotoは綺麗なgoto② • 同じファイル上にしかジャンプできない • 同じコンテキストにしかジャンプできない • 関数の内外や、ループの内外を行き来できない 87 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
ちゃんと帰りたい 88 関数を呼び出す前に 「戻り先」を記録しておき $returnTo = 'return_1'; goto today; return_1:
echo '---'; $returnTo = 'return_2'; return_2: echo 'endʂ'; exit(); スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
ちゃんと帰りたい 89 関数の最後は 「振り分けロジック」へと 飛ぶようにして today: echo date('Y-m-d'); goto return_1;
goto return_dispatcher; スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
ちゃんと帰りたい 90 「戻り先」のメモに応じて 振り分けてジャンプ return_dispatcher: if ($returnTo === 'return_1') goto
return_1; if ($returnTo === 'return_2') goto return_2; 力技で 飛び先となるラベルを全列挙★ スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
初めてのfunction② 関数をスパゲッティにするために、次の挙動を再現する必要がある ✔ 呼び出した場所へ戻れる 2. 1つの値を呼び出し元に返せる 3. 関数の中から関数を呼び出せる 4. ローカルな変数を扱える
91 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
返して欲しい コレ、どうしますか? 92 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $date
= today(); echo $date; function today() { return date('Y-m-d'); } 値を受け取って 変数に代入
返して欲しい 返り値用の専用変数を作る。 呼び出し元・呼び出し先で 同じ変数を読み書きする 93 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi
#a $returnTo = 'return_1'; goto today; return_1: $today = $returnVal; echo $today; exit(); today: $returnVal = date('Y-m-d'); goto return_dispatcher; グローバル変数、 最高〜!
初めてのfunction③ 関数をスパゲッティにするために、次の挙動を再現する必要がある ✔ 呼び出した場所へ戻れる ✔ 1つの値を呼び出し元に返せる 3. 関数の中から関数を呼び出せる 4. ローカルな変数を扱える
94 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい コレ、どうしますか? 95 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a function
countDown() { $days = calcDays(); return "͋ͱ{$days}!!"; } function calcDays() { $kaigi = strtotime('3/20'); return date('z', $kaigi) - date('z'); } echo countDown();
呼びたい 先程の例で導入した 戻り先の振り分けを使うと こんな感じに 96 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi
#a $returnTo = 'return_1'; goto countDown; return_1: echo $returnVal; exit(); countDown: $returnTo = 'return_2'; goto calcDays; return_2: $returnVal = "͋ͱ{$returnVal}!!"; goto return_dispatcher; calcDays: $kaigi = strtotime('3/20'); $returnVal = date('z', $kaigi) - date('z'); goto return_dispatcher;
呼びたい 制御フローだけ抜き出すと こんな感じ 97 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
$returnTo = 'return_1'; goto countDown; return_1: exit(); countDown: $returnTo = 'return_2'; goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher;
呼びたい $returnToを使い回す。 「直近の1つ」しか 戻り先を保持できない 98 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi
#a $returnTo = 'return_1'; goto countDown; return_1: exit(); countDown: $returnTo = 'return_2'; goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher; 呼び出し先の関数内で 上書きされてしまう
呼びたい 99 $returnTo = 'return_1'; goto countDown; return_1: exit(); countDown:
$returnTo = 'return_2'; goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher; 永久に return_2から 抜け出せない $returnToを使い回す。 「直近の1つ」しか 戻り先を保持できない ✕ スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 100 $returnTo = 'return_1'; goto countDown; return_1: exit(); countDown:
$returnTo = 'return_2'; goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher; 複数の戻り先を管理したい 「階層」の概念の導入 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 101 $stackLevel = 0; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto
countDown; 「現在の階層」を管理して スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 102 $stackLevel = 0; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto
countDown; 関数へのジャンプ前 (=「次に進む」前)に インクリメントする スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 103 $stackLevel = 0; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto
countDown; 戻り先を 対応する階層と紐づけて 複数レベルで管理する スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 104 $returnTo = [ 0 => 'return_1', 1 =>
'return_2', ]; 今いる階層に応じて、 return_dispatcherが 戻り先を区別できるように スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 105 return_dispatcher: $stackLevel--; if ($returnTo[$stackLevel] === 'return_1') goto return_1;
if ($returnTo[$stackLevel] === 'return_2') goto return_2; return_dispatcherで、 「戻り先に戻す」直前で 階層レベルを引き下げておく スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 106 // $returnTo = 'return_1'; countDown: $returnTo = 'return_2';
goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher; 永久に return_2から 抜け出せない さっきまでの状況 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
呼びたい 107 // $returnTo[$stackLevel] // = 'return_1' countDown: $stackLevel++; $returnTo[$stackLevel]
= 'return_2'; goto calcDays; return_2: goto return_dispatcher; calcDays: goto return_dispatcher; leve=0なので、 return_1に戻る 新しい状況 leve=1なので、 return_2に戻る スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
初めてのfunction④ 関数をスパゲッティにするために、次の挙動を再現する必要がある ✔ 呼び出した場所へ戻れる ✔ 1つの値を呼び出し元に返せる ✔ 関数の中から関数を呼び出せる 4. ローカルな変数を扱える
108 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
混ざりたくない コレ、どうしますか? 109 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $v
= 14; echo foo($v); function foo($v): float { $rate = 1.05; return $v * $rate; }
混ざりたくない 110 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $v =
14; echo foo($v); function foo($v): float { $rate = 1.05; return $v * $rate; } 関数の外の変数と 名前が被っているけど 区別しなくてはいけない
混ざりたくない 関数呼び出し = 新しい階層の作成。 ローカル変数の区別にも 「階層で分ける」が使える 111 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a $v = 14; echo foo($v); function foo($v): float { $rate = 1.05; return $v * $rate; }
混ざりたくない 呼び出し側: 引数の位置ごとに、 階層と値をマッピングした 辞書を作成する 112 スライド → https://20260322.nichiyou.be ハッシュタグ
→#phperkaigi #a $v = 14; $stackLevel++; $arg0[$stackLevel] = $v; $returnTo[$stackLevel] = 'return_1'; goto foo; return_1: echo $returnVal; exit(); $v = 1; echo foo($v);
混ざりたくない 関数側: 引数の辞書から 「ローカル変数」に写して 処理を進める 113 スライド → https://20260322.nichiyou.be ハッシュタグ
→#phperkaigi #a foo: $paramFuncFoo_v = $arg0[$stackLevel]; // $rateΛνΣοΫͯ͠ॳظԽ; $rate[$stackLevel] = 1.05; $returnVal = $paramFuncFoo_v * $rate[$stackLevel]; goto return_dispatcher; function foo($v) { $rate = 1.05; return $v * $rate; }
混ざりたくない 関数側: 通常のローカル変数も 「何階層目で呼ばれたか」 を管理する 114 スライド → https://20260322.nichiyou.be ハッシュタグ
→#phperkaigi #a foo: $paramFuncFoo_v = $arg0[$stackLevel]; // $rateΛνΣοΫͯ͠ॳظԽ; $rate[$stackLevel] = 1.05; $returnVal = $paramFuncFoo_v * $rate[$stackLevel]; goto return_dispatcher; function foo($v) { $rate = 1.05; return $v * $rate; }
初めてのfunction 関数をスパゲッティにするために、次の挙動を再現する必要がある ✔ 呼び出した場所へ戻れる ✔ 1つの値を呼び出し元に返せる ✔ 関数の中から関数を呼び出せる ✔ ローカルな変数を扱える
115 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a コレで 関数の基本的な機能が できた!
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 次の話 116
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a ・・・に行きたいのですが、 時間は有限なので ココにいる皆さんで次の話を決めません? ※
残り時間を5分以上残せていた場合 117
goto ??? <§3後編: 実演Ⅱ・入り組んだ処理> 1. クラスの基本的な話(プロパティやメソッドの表現) 2. `$this` ってどうやってるの? <§4:
限界、そして言語の壁> 1. 組み込みクラス 2. オペコード上に表れてこないデータ 3. 対応が難しそうで見送っているもの <それ以外> 1. 継承やinstanceofの再現 118 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a class
初めてのclass クラスを、基本的に「データ」「手続き」の集合であるとみなしてみる 1. プロパティ = 連想配列のキーと値みたいなもの 2. メソッド = goto
+ return_dispatcherを使った手続きみたいなもの 121 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
まとめたい 例えばこんなの 122 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a class
Foo { public $v; public function get7X() { return $this->v * 7; } } $foo = new Foo(); $foo->v = 1111; echo $foo->get7X();
まとめたい 基本的な構造はこうなる 123 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $foo
= ['class' => 'Foo']; $foo['v'] = 1111; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto Foo_get7x; $foo = new Foo(); $foo->v = 1111; echo $foo->get7X();
$foo = new Foo(); $foo->v = 1111; echo $foo->get7X(); まとめたい
インスタンス化 = クラス情報を与えた配列 124 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $foo = ['class' => 'Foo']; $foo['v'] = 1111; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto Foo_get7x;
$foo = new Foo(); $foo->v = 1111; echo $foo->get7X(); まとめたい
プロパティへの代入 = 連想配列へのセット 125 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $foo = ['class' => 'Foo']; $foo['v'] = 1111; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto Foo_get7x;
$foo = new Foo(); $foo->v = 1111; echo $foo->get7X(); まとめたい
メソッド呼び出し = gotoでのジャンプ 126 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a $foo = ['class' => 'Foo']; $foo['v'] = 1111; $stackLevel++; $returnTo[$stackLevel] = 'return_1'; goto Foo_get7x;
初めてのclass クラスが基本的に「データ」「手続き」の集合であるとみなしても、 他にも考えないことがいくつもある 1. 同じクラスから別々のインスタンスを作成できる 2. インスタンスごとに`$this` を使える 127 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
初めてのclass クラスが基本的に「データ」「手続き」の集合であるとみなしても、 他にも考えないことがいくつもある 1. 同じクラスから別々のインスタンスを作成できる 2. インスタンスごとに`$this` を使える 128 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a このトークでは こちらだけ紹介!
$thisしたい もちろん、 これだと問題がある 129 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
Foo_get7x: $returnVal = $this->v * 7; goto return_dispatcher; public function get7X() { return $this->v * 7; } 😠
$thisしたい 考えてみると、 $this表現が使われるのは メソッドの中だけ メソッドの内側のことだけ 考えれば良い 130 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a Foo_get7x: $returnVal = $this->v * 7; goto return_dispatcher;
$thisしたい メソッドの内側でだけ・・? それなら、 ローカル変数と同じ考え方が 通用しそう 階層ごとに 今の$thisを記録しておく 131 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a Foo_get7x: $returnVal = $this->v * 7; goto return_dispatcher;
$thisしたい 呼び出し側: 生成したインスタンスごとに 固有のIDを用意し、 IDを使ってオブジェクトを参 照できるようにする 132 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a // ॳظԽ $objects = []; $objIdCounter = 0; $_this = []; $objIdCounter++; $objects[$objIdCounter] = [ 'class' => 'Foo', ]; $objects[$objIdCounter]['v'] = 1111; 生成(new Class)する度に インクリメント
$thisしたい 呼び出し側: 生成したインスタンスごとに 固有のIDを用意し、 IDを使ってオブジェクトを参 照できるようにする 133 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a // ॳظԽ $objects = []; $objIdCounter = 0; $_this = []; $objIdCounter++; $objects[$objIdCounter] = [ 'class' => 'Foo', ]; $objects[$objIdCounter]['v'] = 1111; IDを使って インスタンス管理
$thisしたい 呼び出し側: メソッドへのジャンプ前に、 $thisという配列で、 インスタンスIDを 今から使う階層にマッピング 134 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a $stackLevel++; $returnTo[$stackLevel] = 'return_1'; $this[$stackLevel] = $objIdCounter; goto Foo_get7x; 引数と同じノリ。 「階層に閉じた値」となる
$thisしたい 関数側: 現在の階層の情報を用いて、 オブジェクト(ID)マップから 自インスタンスでのthisに当 たるデータを取得する 135 スライド → https://20260322.nichiyou.be
ハッシュタグ →#phperkaigi #a Foo_get7x: $tmpObjectId = $this[$stackLevel]; $tmpThis = $objects[$tmpObjectId]; $returnVal = $tmpThis['v'] * 7; goto return_dispatcher;
$thisしたい 136 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a Foo_get7x: $tmpObjectId
= $this[$stackLevel]; $tmpThis = $objects[$tmpObjectId]; $returnVal = $tmpThis['v'] * 7; goto return_dispatcher; 今のコンテキストでの オブジェクトのIDを取得
$thisしたい 137 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a Foo_get7x: $tmpObjectId
= $this[$stackLevel]; $tmpThis = $objects[$tmpObjectId]; $returnVal = $tmpThis['v'] * 7; goto return_dispatcher; そのIDに紐づいている データを取得
$thisしたい 138 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a Foo_get7x: $tmpObjectId
= $this[$stackLevel]; $tmpThis = $objects[$tmpObjectId]; $returnVal = $tmpThis['v'] * 7; goto return_dispatcher; あとはそのまま参照すればOK
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
done!
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 組み込みクラス 141
組み込みクラス - 問題 • 夢の無限スパゲッティ製造機は、 ソースコードを読むことで「メソッドごとにラベルに」変換している • 標準/拡張で定義されているクラスの内容を、PHPで読むのは厳しい 142 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
組み込みクラス - 対応 • 不思議なヘルパー関数を用意することで対処 • FFIのような、PHPの機能をPHPで呼び出すための仕組み 143 スライド →
https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
クラスの例 ネイティブの \DateTimeImmutable を 利用しているクラスを定義 144 スライド → https://20260322.nichiyou.be ハッシュタグ
→#phperkaigi #a class D extends \DateTimeImmutable { } $d = new D(); echo $d->format('c');
クラスの例 new や メソッドコールを ヘルパーを介して実行する 145 スライド → https://20260322.nichiyou.be ハッシュタグ
→#phperkaigi #a $d = __builtin_new('D', []); $x = __builtin_call( $d, 'format', ['c'] ); echo __builtin_unwrap($x);
組み込みクラス - 対応 • __builtin〜〜系メソッドの対象か否かを判別する必要がある • bootstrap処理で、get_declared_classes() からクラスを洗い出す • オペコードからの変換時に定義済みクラス
or NOTを区別 146 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a オペコード上に表れてこないデータ 147
定数配列 • 次のコードのオペコードを生成すると、 • 通常は、このように配列の中身が現れない • 夢の無限スパゲッティ製造機だと、こうなる $config1 = ['name'
=> 'test', 'value' => 42]; L0003 0000 ASSIGN CV0($config) array(...) 3: ASSIGN CV0($config1) "[\'name\' => \'test\',\'value\' => 42]" 148 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
valueに 定数を使った配列
🍝
値がない配列を見つけたら
元のコードの行番号を取って
token_get_allで解析
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], token_get_allの結果 (説明用に整形しています)
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], 0:トークンの識別ID 1: ソース 2: 行番号
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], array(…)があった 「2行目」のトークンを探して
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], array の開始位置を見つけたら
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], そこから「配列の中身」を抜き出す = "[" と "]" の間のトークン
"=", [397, " ", 2], "[", [269, "'name'", 2], [397,
" ", 2], [391, "=>", 2], [397, " ", 2], [269, "'test'", 2], ",", [397, " ", 2], [269, "'value'", 2], [397, " ", 2], [391, "=>", 2], [397, " ", 2], ['name' => 'test', 'value' => 42]
ちなみに: valueに変数を使った配列の場合 160 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 技術的制約を感じて 実装を見送っているもの 161
include/requireの(完全な)対応 • 夢の無限スパゲッティ製造機は、 include/requireをインラインに展開することで対応している • そのため、`include $file` のような形式は変換できない 162 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
include/requireの(完全な)対応 〜それでも〜 • `include $file` のようなコードはComposerのautoloadでも出てくる • 夢の無限スパゲッティ製造機はComposerの夢を見るか? • →はい、見ます
• 別のアプローチで対応の実装済み • 気になる人はQ&AかAsk The Speakerで聞いてください 163 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
destructor • 通常の実行フローとは異なるタイミングで発火する • これを夢の無限スパゲッティ製造機で扱うことは可能か・・? いずれにせよ「技術的には可能です」のレベル • すなわち、ガベージコレクションに相当するものを作ればOK。多分。 164 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
done!
ちょっとオマケ
発表では触れていないけど、こんなコードも行けます 気になるものがあったら、Ask The Speakerや懇親会でもどうぞ! ※ 上手く答えられるかはモノによります • クラスの継承 • try-catch-finally
• 可変長引数・名前付き引数 • ジェネレータ(yield) ※一部非対応 • 無名関数・無名クラス 167 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a
おまけ • なんやかんやで、 Slimを使ったアプリケーションの スパゲッティ化に成功しました • →のコードが変換元(32行) => 53,957行 •
github.com/o0h/the-spaghetti-dream-gallery を見てみてください • 僕は怖くて中身を見ていません • ただし変換前後のコードに対して 同じ内容のE2Eテストはパス済み(thx runn!) スライド → https://20260322.nichiyou.be 168 ハッシュタグ →#phperkaigi #a
1. スパゲッティの世界と製造機の挑戦 2. 実演Ⅰ・基本的な処理 3. 実演Ⅱ・入り組んだ処理 4. 限界、そして言語の壁 5. 最後に言いたいこと
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a return、やばい めっちゃ凄いし、超便利、 これは人類の叡智。 まだ使ったことない人、急いだ方が良いです!
170
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a ・・・というのは、一分一厘は冗談なのですが 171
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 「日常の範囲に染み付いた構造」から 抜け出すことで、 「当たり前」が「実はスゴい!!」になった 172
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 夢の無限スパゲッティ製造機が 教えてくれたこと 173
スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 我々が生きている、この日常こそが 実は夢だったのかも知れない 174
おしまい! お付き合いいただき ありがとうございました!!
Appendix-Ⅰ 夢の無限スパゲッティ製造機、その処理の全体像
全体フロー 177 コマンド起動/src受け取り オペコード変換 w/phpdbg include require 部分のインライン化 クラス階層・静的プロパティ・enumや定数の解決 スライド
→ https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a 🍝化 冗長なコードのクリーンアップ
Appendix-Ⅱ o0h/phpstan-spaghetti
PHPStan用のルール • https://packagist.org/packages/o0h/phpstan-spaghetti • 静的解析で制御構文等を禁止などの実現 • the-spaghetti-dream.nichiyou.be で利用知れいるのはコレ • 背景などはブログにも書きました
https://daisuki.nichiyoubi.land/entry/2026/02/01/122707 179 スライド → https://20260322.nichiyou.be ハッシュタグ →#phperkaigi #a