Skip to content

PHP縛りゲーの世界

公開日:

東京都渋谷区GMO Yoursで開催された『第136回 PHP勉強会@東京』でライトニングトーク(5分)として発表しました。

Download PDF

スライドテキスト

Page 1

PHP縛りゲーの世界

第136回 PHP勉強会@東京2019年3月27日 #phpstudy

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE
  • GitHub/Packagistでは id: zonuexe
  • ピクシブ株式会社 pixiv運営本部
  • Emacs Lisper, PHPer
  • Emacs PHP Modeのメンテナ引き継ぎました
  • 好きなリスプはEmacs Lispです
  • Qiitaに記事を書いたり変なコメントしてるよ

Page 3

待ってるにょ

Page 4

Page 5

Page 6

宣伝

Page 7

今週末はPHPerKaigiです

Page 8

CIとか静的解析の話をします

Page 9

チケットを持ってない人は今すぐ購入

Page 10

さてみなさん

Page 11

プログラミングは好きですか?

Page 12

プログラミングは楽しいですか?

Page 13

もっと楽しくしたくないですか?

Page 14

そうですね

Page 15

制約を課すべし

Page 16

ゲームをプレイする際、本来ゲーム側からは設定されていない制限(縛り)を自ら科す事によって、より難易度の高いゲームをプレイする事。

–ニコニコ大百科

https://dic.nicovideo.jp/a/%E7%B8%9B%E3%82%8A%E3%83%97%E3%83%AC%E3%82%A4

Page 17

他言語における実例

Page 18

セミコロンレスJava

常識的なJavaは、式文の末尾にセミコロン(;)を要求

ところが、工夫することで ;の挿入を回避してコードを書くことが可能

Page 19

Pythonワンライナー

Pythonはインデントベースの文法(オフサイドルール)を持つため、改行を要求する文法が多い……が、さまざまなテクを駆使することでこの制約を回避

Page 20

それならPHPは

Page 21

セミコロンレスPHP

PHPもJavaと同じく式文の末尾にセミコロン(;)を要求する

だが実はPHPは ?> 直前の ; を省略できる

?> も禁止することで成立する

Page 22

ワンライナーPHP

PHPは改行が文法的な意味を(ほぼ)持たず ; で区切って複数の式文を一行に書ける

Pythonと同等の難易度にはならない

Page 23

どうしよう

Page 24

🤔

Page 25

🤑

Page 26

Page 27

PHPにおける $ とは

言わずと知れた変数のシンボル(sigil)

おそらくPerlに由来するが、Perlの意味とはまったく異なる

実際いろんなところで必須

Page 28

PHPにおける $

<?php

function foo($a, $b) {$name = "hoge"; // 変数代入var_dump($_SERVER); // ← スーパーグローバル変数

foreach (piyo() as $p) { // ← 省略できないecho $piyo->$name; // ← 可変プロパティ}}

Page 29

どうしよう

Page 30

(2回め)

Page 31

変数を利用できない=状態の更新ができない

Page 32

🙃

Page 33

大丈夫です

Page 34

$なしで意外と書けます

Page 35

FizzBuzzは書けます

Page 36

どうすんの

Page 37

PHPにおける $

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 38

PHPにおける $

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

定数定義 ($不要)

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 39

PHPにおける $

無名関数を起動

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 40

PHPにおける $

FizzBuzzのロジック

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 41

PHPにおける $

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

100から0になるまで、自分自身の関数を呼び出す

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 42

PHPにおける $

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

FizzBuzzをプリント

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 43

PHPにおける $

<?php const FB = ['FizzBuzz', null, null, 'Fizz', null,'Buzz', 'Fizz', null, null, 'Fizz', 'Buzz', null,'Fizz', null, null];

引数をとる

call_user_func(new class { function __invoke() {if (func_get_arg(0) -1 )call_user_func(__METHOD__, func_get_arg(0) - 1);echo FB[func_get_arg(0) % 15] ?? func_get_arg(0), "\n";}}, 100);

Page 44

変数禁止って言ってんのにfunc_get_arg(0)使ってるのずるくね?

Page 45

ずるいとってもずるい

Page 46

しかしfunc_get_arg()を禁止すると関数が完全に利用不能になるので難易度急上昇↑↑

Page 47

今回は妥協

Page 48

今回は再帰呼び出しすることで状態更新を回避

Page 49

さらなる難易度を求めるあなたへ

Page 50

難易度を下げる関数を禁止

状態を持てる関数

APCu, getenv(), ini_get()

変数テーブルの操作

compact(), extract()

Page 51

難易度を下げる関数を禁止

定数の動的定義

define(), constant()

更新不能のグローバル変数として状態を持てるため

禁止する文字を増やす

{} とか : とか(両方は重い)