てきとうなさいと べぇたばん

PHPのソースを読もう てきめんのPHPソース追っかけ冒険記 PHP Advent Calendar 2015 11日目

PHPつかってるかい!?

みなさんこんにちは。なんかさいきん、あんたとしいくつだよとか言われるようになったてきめんです!

PHPのソースって読んでるかい!?

とか言いながら、ぼくはPHP7のソースはちょっとしか読んでいません。とはいえ、php-astとか面白そうで闇PHP勉強会の時はノリノリで覗いていました。 だからこそ、どんどんソースを読んでいきたいです。今回はソースコードを追っていったぼくの歴史を話そうかと思います。

どうやって動いているのだろう - 関数編 -

最初に見つけたのが関数でした。どうやって動いているのだろうって気になりだしてついに。

fgetcsv

最初にPHPのソースを読もうと思った動機は「fgetcsvの挙動がわからん」でした。わからないならソースコードよんでしまえっっていうノリで。でもですね、解読不可能だったんですよ…

https://github.com/php/php-src/blob/master/ext/standard/file.c#L1985

今読んでもちょっとめまいしてきた…

session_save_handler

PHPのSESSIONで、いきなり想定の時間より早くきれてしまうことがよくありました。そんな時、ぐぐってもなかなか答えが出ない。しゃーない。ソース読むぞ

http://tekitoh-memdhoi.info/views/330

ということで、読んだら結構簡単でした。同じディレクトリにセッションファイル入れちゃダメよんっていうだけでした。

PHP関数の引数

そんなかんじでいつも通りにソースコードを漁っていると引っかかったのが「関数の引数」でした。PHPは関数の引数の個数を間違えたり、引数を文字列としているところに配列を入れると予想外の挙動をすることがわかりました。

http://tekitoh-memdhoi.info/views/577

海老原さんの記事のほうが早かった。

どうやって動いているのだろう - コアら編 -

関数だけ読んでても面白くなかったので、PHPそのものがどのように動いているのか知りたくなりました。

構文解析

PHPの挙動自体が知りたくなってきたので、色々調べてみました。 気になったのが、Zend/zend_language_parser.yでした。これってなんだろう?と思い探してみると、Bisonと呼ばれる構文解析器のことでした。

Bisonで検索すると、徳丸先生のページが見つかりました。2000年ごろに書かれたようですが、全然使えてしまいました。セキュリティ以外で教えを請うことになるとは(当然、こういう知識がないとできない仕事だとは思います)。ありがとうございます。ひげぽんさんのページも参考にさせていただきました。

字句解析

Bisonを調べた結果、re2cを使う、すなわち字句解析ツールを使用することがわかってきました。

前述のBison、re2cの実装共にakkera102さんのページが参考になりました。ありがとうございます。

そしたら電卓作ろうぜ!

というわけで出来たのがcalc-modokiです。これは最近は特に何もしてません。相変わらず「DO NOT PRODUCTION USE」です。

http://tekitoh-memdhoi.info/views/624

これがきっかけで「インタプリタってどうやって作ればいいのだろう」という疑問が湧いてきます。

PHPのバージョンアップで起こったへんてこなアップデート

PHP5.5.16と5.4.32にて修正されたバグのうち、もちろんセキュリティアップデートもありましたが、なんとしれっとこんなバグも修正されました。

<?php
$b=array(-1=>0);
$c=array_pop($b); assert($c == 0);

assert(array_push($b, 0), 1);
assert(array_push($b, 0), 2);
var_dump($b);
assert(array_push($b, 0), 3);
?>

array(2) {
  [-1]=>
  int(0)
  [9223372036854775807]=>
  int(0)
}
PHP Warning:  array_push(): Cannot add element to the array as the next element is already occupied in /home/tekitoh/php/test.php on line 11
PHP Warning:  assert(): 3 failed in /home/tekitoh/php/test.php on line 11

まとめたページはhttp://tekitoh-memdhoi.info/views/632になりますが、これをきっかけにPHPのバージョンアップにはChangelogを絶対覗くべきだと確信しました。

また、PHPのarrayの挙動に関しても謎が出てきました。なんでBucket構造体のhはunsigned longなのでしょう?という謎です。PHPカンファレンスや闇PHP勉強会で誰に聞いても未だにわからない…

やっぱりまたやらかしてた

5.5.25と5.6.9のTraitで。みんなコレ知ってるのかな?#69467 Wrong checked for the interface by using Trait

Test script:
---------------
interface Baz {
    public function bad();
}

trait Bar{
    protected function bad(){}
}

class Foo implements Baz{
    use Bar;
}

$test = new Foo();
var_dump($test instanceof Baz);

Expected result:
----------------
Fatal error

Actual result:
--------------
bool(true)

そもそも、Trait周りは結構バグ多い印象ありますね。いま読んでみると。

そしたらインタプリタ作ろうぜ!

やっぱここまでいくとインタプリタ作りたくなるじゃないですか。作ってみました。ちょうどいい本があったので。

http://tekitoh-memdhoi.info/views/661

てきめんラジコンにぶちこんでやったぜ

これはJavaですが、声を使って命令する際に字句解析、構文解析のやり方を参考にさせてもらいましたへへへ

http://tekitoh-memdhoi.info/views/688

ソースコードの追い方

ぼくはとりあえず以下のツールがあればどうにか読めます。

  • vim
  • grep
  • ctags
  • php-vld
  • gdb

PHPでのgdbの使い方は、ヤフーさんの記事が参考になります。http://techblog.yahoo.co.jp/tips/php/

関数の挙動であれば

ぼくは、関数の挙動であれば、ソースのディレクトリ下でgrepをかけます。

$ grep -lr 'PHP_FUNCTION(fgetcsv' .

あとは、GNU ctagsは必須ですね。

$ ctags -R .

そして、viで掘っていきます。

$ vi ext/standard/file.c

その中でまた検索でもかければ良いんじゃないかなぁ。

ありがとうございました。

気がついたらたらたら長い文章になってしまいました。ていうかただの自分語りポエムになってしまいましたねヽ(^。^)ノ

とはいえ、PHPのソースコードを追っかけるというのは慣れれば楽しいです。さあ、みんなでPHPのソースを追っかけよう!