Upload
yuya-takeyama
View
903
Download
0
Embed Size (px)
DESCRIPTION
PHP の良いパーツとして stream, Iterator, Generator を紹介します。 これらはファイルやコレクションに対して統一的な操作を提供し、小さな関数を組み合わせた関数型プログラミング的なアプローチの助けになります。 また、そういったテクニックの根底にある、UNIX 哲学についても紹介します。
Citation preview
Good Parts of PHP and
The UNIX Philosophy@ PHP カンファレンス 2014 フィードバックはこちら
https://joind.in/talk/view/12040
自己紹介
• Twitter: @yuya_takeyama
• GitHub: yuya-takeyama
• PHP / Ruby / Golang
Good Parts•Stream •Iterator •Generator
The UNIX Philosophy
これがUNIXの哲学である。 一つのことを行い、またそれをうまくやるプログラムを書け。 協調して動くプログラムを書け。 標準入出力(テキスト・ストリーム)を扱うプログラムを書け。標準入出力は普遍的インターフェースなのだ。
— M. D. マキルロイ、UNIXの四半世紀
http://ja.wikipedia.org/wiki/UNIX哲学
ひとつのことをうまくやれ
全てのプログラムをフィルタに
部分の総和は全体よりも大きい
対象者•ライブラリを書く人
効用•再利用性の高いコード
•組み合わせられるコード
•が書けるようになる
話さないこと
•並列・並行プログラミング
Stream
$fp = fopen($file, 'r');
Stream•データの流れ
•データを読み込めるかも
•データを書き込めるかも
<?php $source = fopen('./input.txt', 'r'); $dest = fopen('./output.txt', 'w'); if ($source && $dest) { while (($buf = fgets($source, 8192)) !== false) { if (fputs($dest, $buf) === false) { throw new RuntimeException('write error'); } } if (feof($source) === false) { throw new RuntimeException('read error'); } fclose($source); fclose($dest); }
ファイルの読み書き
<?php $source = fopen('./input.txt', 'r'); $dest = fopen('./output.txt', 'w'); if ($source && $dest) { while (($buf = fgets($source, 8192)) !== false) { if (fputs($dest, $buf) === false) { throw new RuntimeException('write error'); } } if (feof($source) === false) { throw new RuntimeException('read error'); } fclose($source); fclose($dest); }
ファイルの読み書き
わりと むずい
何が便利?
Stream wrapper
Stream wrapper• あらゆるものをfopen()可能に!
• 標準インターフェイスとしてのストリーム (または URL)!
• ユーザによる実装も可能
$fp = fopen($url);
file_get_contents($url);
Protocols•file://!
•http(s)://!
•ssh2.sftp://!
•etc…
Formats•phar://!
•zip://!
•rar://!
•etc…
Specials•php://stdin!
•php://memory!
•php://temp!
•etc…
Stream wrapper を
実装する
http://php.net/manual/ja/class.streamwrapper.php
http://php.net/manual/ja/class.streamwrapper.php
かなり だるい
実例
http://docs.aws.amazon.com/aws-sdk-php/guide/latest/feature-s3-stream-wrapper.html
標準インターフェイス
Stream wrapper x
Symfony
http://fabien.potencier.org/article/44/php-iterators-and-streams-are-awesome
http://fabien.potencier.org/article/44/php-iterators-and-streams-are-awesome
ひとつのことをうまくやれ
全てのプログラムをフィルタに
部分の総和は全体よりも大きい
http://fabien.potencier.org/article/44/php-iterators-and-streams-are-awesome
Stream Wrapper を利用することで、あらゆるプロトコル・フォーマットを抽象化して操作できる
Stream をフィルタする!プログラムを作って!組み合わせよう
Conclusion of Stream
Iterator
Iterator (in General)•要素の集合
•各要素に順番にアクセス
•リストのような何か
Iterator (in PHP)•Traversable インターフェイス!
•foreach できる何か
Iterator を
実装する
http://jp1.php.net/manual/ja/class.iterator.php
RangeIterator をつくる
RangeIterator•最初と最後の値を指定する!
•その値の幅を表すイテレータ!
•各ステップごとの増加数も指定できる
http://qiita.com/yuya_takeyama/items/51fb058ed20d3df8209e
$range = new RangeIterator(1, 10); foreach ($range as $n) { echo $n, PHP_EOL; }
RangeIterator を使う
1 !
!
!
RangeIterator を使う
1 2 !
!
RangeIterator を使う
1 2 3 !
RangeIterator を使う
1 2 3 4
RangeIterator を使う
1 2 3 4 …
RangeIterator を使う
Range といえば….
http://php.net/range
range() vs
Rangeiterator
range()
•要素数文の array を予め生成!
•その文メモリを消費
RangeIterator•各ループ時に次の値を計算して生成!
•要素数が増えてもメモリ量は一定!
•無限リストの生成も可能
$range = new RangeIterator(1, INF); foreach ($range as $n) { echo $n, PHP_EOL; }
無限リストを使う
$range = new RangeIterator(1, INF); $range = new LimitIterator($range, 2, 100); foreach ($range as $n) { echo $n, PHP_EOL; }
無限リストを切り取って使う
3 !
!
!
無限リストを切り取って使う
3 4 !
!
無限リストを切り取って使う
3 4 5 !
無限リストを切り取って使う
3 4 5 …
無限リストを切り取って使う
イテレータは
組み合わせられる
イテレータが
別のイテレータを
生成する
ひとつのことをうまくやれ
全てのプログラムをフィルタに
部分の総和は全体よりも大きい
$dir = new RecursiveDirectoryIterator( '/Users/yuya/Music/iTunes/iTunes Media/Music/Aphex Twin' ); $dir = new RecursiveIteratorIterator($dir); $dir = new CallbackFilterIterator($dir, function ($node) { return $node->isFile(); }); $dir = new CallbackFilterIterator($dir, function ($file) { return preg_match('/^01/', $file->getFilename()); }); !foreach ($dir as $file) { echo $file, PHP_EOL; }
イテレータでファイル検索
01 Come To Daddy (Pappy Mix).mp3 !
!
!
イテレータでファイル検索
01 Come To Daddy (Pappy Mix).mp3 01 4.m4a !
!
イテレータでファイル検索
01 Come To Daddy (Pappy Mix).mp3 01 4.m4a 01 minipops 67 [120.2] [source field mix].m4a !
イテレータでファイル検索
01 Come To Daddy (Pappy Mix).mp3 01 4.m4a 01 minipops 67 [120.2] [source field mix].m4a 01 Windowlicker (Original Demo).mp3
イテレータでファイル検索
01 Come To Daddy (Pappy Mix).mp3 01 4.m4a 01 minipops 67 [120.2] [source field mix].m4a 01 Windowlicker (Original Demo).mp3 01 Windowlicker.mp3
イテレータでファイル検索
イテレータは
組み合わせられる
イテレータが
別のイテレータを
生成する
標準インターフェイス
としての
イテレータ
Generator
Generator• PHP5.5~
• Iterator の一種
•ひとつの関数だけで作れる
$gen = function () { yield 1; yield 2; yield 3; }; !
foreach ($gen() as $n) { echo $n, PHP_EOL; }
ジェネレータを使ってみる
1 !
ジェネレータを使ってみる
1 2
ジェネレータを使ってみる
1 2 3
ジェネレータを使ってみる
$range = function ($start, $end, $step = 1) { for ($i = 1; $i <= $end; $i += $step) { yield $i; } }; !
foreach ($range(1, 100) as $n) { echo $n, PHP_EOL; }
ジェネレータでrange
http://qiita.com/yuya_takeyama/items/51fb058ed20d3df8209e
$range = function ($start, $end, $step = 1) { for ($i = 1; $i <= $end; $i += $step) { yield $i; } }; !
foreach ($range(1, 100) as $n) { echo $n, PHP_EOL; }
ジェネレータでrange
$range = function ($start, $end, $step = 1) { for ($i = 1; $i <= $end; $i += $step) { yield $i; } }; !
foreach ($range(1, 100) as $n) { echo $n, PHP_EOL; }
ジェネレータでrange
圧倒的に 簡潔
Functional Programming
with Generator
nikic/iter
•コレクション操作関数群
• range/map/filter/reduce •イテレータを受けてジェネレータを返す
ひとつのことをうまくやれ
全てのプログラムをフィルタに
部分の総和は全体よりも大きい
まとめ•Stream と Iterator は PHP の標準インターフェイスである
•これらをフィルタする関数を組み合わせることで、あらゆるロジックを表現することができる
•ジェネレータにより柔軟にイテレータを生成できる
Thank you for
Listening