Page 1
PHP縛りゲーの世界
第136回 PHP勉強会@東京2019年3月27日 #phpstudy
公開日:
by USAMI Kenta@tadsan
に東京都渋谷区のGMO Yoursで開催された『第136回 PHP勉強会@東京』でライトニングトーク(5分)として発表しました。
第136回 PHP勉強会@東京2019年3月27日 #phpstudy
待ってるにょ
宣伝
今週末はPHPerKaigiです
CIとか静的解析の話をします
チケットを持ってない人は今すぐ購入
さてみなさん
プログラミングは好きですか?
プログラミングは楽しいですか?
もっと楽しくしたくないですか?
そうですね
制約を課すべし
ゲームをプレイする際、本来ゲーム側からは設定されていない制限(縛り)を自ら科す事によって、より難易度の高いゲームをプレイする事。
–ニコニコ大百科
https://dic.nicovideo.jp/a/%E7%B8%9B%E3%82%8A%E3%83%97%E3%83%AC%E3%82%A4
他言語における実例
セミコロンレスJava
常識的なJavaは、式文の末尾にセミコロン(;)を要求
ところが、工夫することで ;の挿入を回避してコードを書くことが可能
Pythonワンライナー
Pythonはインデントベースの文法(オフサイドルール)を持つため、改行を要求する文法が多い……が、さまざまなテクを駆使することでこの制約を回避
それならPHPは
セミコロンレスPHP
PHPもJavaと同じく式文の末尾にセミコロン(;)を要求する
だが実はPHPは ?> 直前の ; を省略できる
?> も禁止することで成立する
ワンライナーPHP
PHPは改行が文法的な意味を(ほぼ)持たず ; で区切って複数の式文を一行に書ける
Pythonと同等の難易度にはならない
どうしよう
🤔
🤑
$
PHPにおける $ とは
言わずと知れた変数のシンボル(sigil)
おそらくPerlに由来するが、Perlの意味とはまったく異なる
実際いろんなところで必須
<?php
function foo($a, $b) {$name = "hoge"; // 変数代入var_dump($_SERVER); // ← スーパーグローバル変数
foreach (piyo() as $p) { // ← 省略できないecho $piyo->$name; // ← 可変プロパティ}}
どうしよう
(2回め)
変数を利用できない=状態の更新ができない
🙃
大丈夫です
$なしで意外と書けます
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);
<?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);
無名関数を起動
<?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);
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);
<?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);
<?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);
<?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);
変数禁止って言ってんのにfunc_get_arg(0)使ってるのずるくね?
ずるいとってもずるい
しかしfunc_get_arg()を禁止すると関数が完全に利用不能になるので難易度急上昇↑↑
今回は妥協
今回は再帰呼び出しすることで状態更新を回避
さらなる難易度を求めるあなたへ
難易度を下げる関数を禁止
状態を持てる関数
APCu, getenv(), ini_get()
変数テーブルの操作
compact(), extract()
難易度を下げる関数を禁止
定数の動的定義
define(), constant()
更新不能のグローバル変数として状態を持てるため
禁止する文字を増やす
{} とか : とか(両方は重い)
