Skip to content

PHPにおけるメタプログラミングの温床

公開日:

東京都大田区日本工学院専門学校 蒲田キャンパスで開催された『Learn Languages 2017』でライトニングトーク(5分)として発表しました。

Download PDF

スライドテキスト

Page 1

における

メタプログラミングの温床

Meta programming for PHP

2017-08-20 NEEC Kamata #ll2017jp ODC 2017 Tokyo/ Learn Languages (LL2017)

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE
  • GitHub/Packagistでは id: zonuexe
  • Emacs Lisper, PHPer
  • Qiitaに記事を書いたり変なコメントしてるよ
  • 動的言語はコンピューティングの真髄

Page 3

世の中にはいろんなクールな言語がある

Page 4

PHPには毛ほども興味のなさそうな皆さまにPHPの動的な言語機能を紹介します

Page 5

サンプルコードは言語機能を簡易に紹介するためのものです

Page 6

利用の際は必要性と利便性を慎重に判断すること。(メタプログラミングって基本的にそーゆーものですけど…)

Page 7

アジェンダ

Page 8

0. 前提1. 初級篇2. 中級篇3. 上級篇

Page 9

前提

Page 10

PHPは、所謂LLとしては遊びが少ない

Page 11

例) 原則として関数やクラスを再定義できない(致命的エラーが発生)

Page 12

RubyやPythonと違ってオープンクラスではない(モンキーパッチができない)

Page 13

謎なタイミングでクラス定義が変更されることが(基本的には)ない

Page 14

=静的解析しやすい条件が揃ってる

Page 15

その和を乱す邪悪な動的メタプログラミングテクニックが存在する

Page 16

😇

Page 17

初級編

Page 18

callable

Page 19

関数として呼出し可能な値を表す擬似型

Page 20

callable

// After$f = $cond ? 'foo' : 'bar';call_user_func($f, $var);

// Before if ($cond) {foo($var);} else {bar($var);}

// こうやって書いてもいい$f($var);

Page 21

map

$ary = ["apple", "orange", "banana"];//=> ["Apple", "Orange", "Banana"]

$bry = [];foreach ($ary as $i => $a) {

$cry =array_map('ucfirst', $ary);

$bry[$i] => ucfirst($a);}

Page 22

compact()extract()

Page 23

変数テーブルにアクセスできる関数

Page 24

compact()変数テーブルから取り出して配列にする

Page 25

compact()

$foo = foo();$bar = bar();

hoge(compact('foo','bar'));

hoge(['foo' => $foo,'bar' => $bar]);

Page 26

extract()変数テーブルから取り出して配列に

Page 27

extract()

function (array $vs){

extract($vs,

EXTR_PREFIX_ALL,

$hoge_foo = $vs['foo'];$hoge_bar = $vs['bar'];

'hoge');

本当はissetでチェックすべき

Page 28

extract()未使用変数の検出できない

読みにくくなるので邪悪

バグの温床であるばかりか、ふつうに脆弱性の温床になる

Page 29

$$var

Page 30

$$var可変変数(variable variables)

Page 31

可変変数

$world = "こんにちは世界";$hello = "world";$v = "hello";

var_dump($v); //=> "hello"var_dump($$v); //=> "world"var_dump($$$v); //=> "こんにちは世界"// $$ はいくつ付けてもよい!!

Page 32

debug_backtrace()

Page 33

スタックトレースを全部取得できる(ファイル・引数含む)

Page 34

(これを悪用すればどんな邪悪なことができるかは明白なので省略)

Page 35

中級編

Page 36

マジックメソッド

Page 37

__get($name)__set($name, $value)

Page 38

__get()アクセス不可プロパティを読み出そうとしたときに呼ばれる

Page 39

__set()アクセス不可プロパティを書き込もうとしたときに呼ばれる

Page 40

__get(), __set()

class Hoge {private $values = [];public function __set($name, $value) {$values[$name] = $value;}public function __get($name) {return $values[$name];}}

Page 41

「アクセス不可」は未定義プロパティだけはなくprivate, protected含む

Page 42

読み出し専用プロパティ

/*** @property-read string $name*/class Hoge {private $name;public function __construct($name) {$this->name = $name;}public function __get($name) {return $values[$name];}

Page 43

書き込み禁止プロパティ

public function __set($name) {throw new OutOfRangeException();}}

Page 44

__call($name, $args)

Page 45

__call()アクセス不可メソッドを起動しようとしたときに呼ばれる

Page 46

Proxyパターン

class HogeProxy {private $hoge;public function __construct(Hoge $hoge) {$this->hoge = $hoge;}public function __call($name, $args) {return call_user_func_array($name, $args);}}

Page 47

Proxyパターン (PHPDoc)

/*** @method Foo getFoo()* @method string format(string $tpl)* @method void close()*/class HogeProxy {/** @var Hoge */private $hoge;public function __construct(Hoge $hoge) {$this->hoge = $hoge;}public function __call($name, $args) {

Page 48

上級編

Page 49

spl_autoload_register()

Page 50

クラスが定義されたファイルを自動ロードするための仕組み

Page 51

(ふつうはComposerがやってくれるので自分で定義する必要ない)

Page 52

ふつうのクラスローダー

spl_autoload_register(function ($class) {$file = strtr($class, '\\', '/') . '.php';$path = __DIR__ . '/' . $file;if (file_exists($path)) {require $path;}});

Page 53

クラスが読み込まれる前に介入できる

Page 54

邪悪クラスローダー

if (file_exists($path)) {$evil_path = evil_path($path);if (file_exists($evil_path)) {$src = file_get_contents($path);// ファイルを魔改造$evil_src = evil_customize($src);file_put_contents($evil_path, $evil_src);}require $evil_path;}

Page 55

まとめ

Page 56

PHPは制限の大い言語のようだが、遊べるポイントはいろいろある

Page 57

大いなる力には大いなる責任がry

Page 58

PHPUnit, PsySH, そのほか一部のフレームワークなどはメタプログラミングのテクニックを活用してる

Page 59

それ用のライブラリもある。(Go! AOP https://github.com/goaop/framework)

Page 60

実用知識!

Page 61

そなえよう