PHP7 ã§å©ç¨ã§ãã php-ast æ¡å¼µã¢ã¸ã¥ã¼ã«ãå°å ¥ãã¦ãPHP ã®ããã°ã©ã ã®ãã¡ã¤ã«ãµã¤ãºã¨æ½è±¡æ§ææ¨ã®ãã¼ãæ°ã®é¢ä¿ããããããã¦ã¿ã¾ãã
PHP7 ã§ã¯ãããã°ã©ã ãå®è¡ããéãæ§æ解æã®çµæãæ½è±¡æ§ææ¨ (Abstract Syntax Tree) ã®å½¢ã«ãã¦ããããããã¤ãã³ã¼ããçæããããã«ãªãã¾ãã*1ãæ½è±¡æ§ææ¨ãä½ã£ã¦ãã§ã¼ãºãåãããã¨ã«ã¯ãã³ã³ãã¤ã©ã®å®è£
ã®è¦éãããããªãããã¾ãã¾ãªæé©åãå®è£
ãããããªããã¨ãã£ãå©ç¹ãããã¾ãããã®ããã«ãã§ã¼ãºãåãããã¨ã¯ã³ã³ãã¤ã©ã®å®è£
ã§ã¯ä¸è¬çã§ãä¸è¨ã® Wikipedia ã®èª¬æã«ãããããã«ãããã¾ãã«ã¯ãæ½è±¡æ§ææ¨ãä½ãã¨ããã¾ã§ã®å¦çãããã³ãã¨ã³ããæ½è±¡æ§ææ¨ã解æãæé©åãã¦å®è¡ã³ã¼ããåºåããå¦çãããã¯ã¨ã³ãã¨å¼ã³ã¾ãã
コンパイラ - Wikipedia
æ½è±¡æ§ææ¨ã¯ã³ã³ãã¤ã©ã®å
é¨ã§å©ç¨ããããã¼ã¿æ§é ã§ãããé常ã¯ç¹ã«æèãããã¨ã¯ããã¾ããããphp-ast ã¨ããæ¡å¼µã¢ã¸ã¥ã¼ã«ãå©ç¨ããã¨ãæ½è±¡æ§ææ¨ã PHP ã®ãªãã¸ã§ã¯ãã¨ãã¦åãåºãã¾ããä»åã¯ãã®ã¢ã¸ã¥ã¼ã«ãå©ç¨ãã¦æ½è±¡æ§ææ¨ã®ãã¼ãæ°ãæ°ãããã¡ã¤ã«ãµã¤ãºã¨ã®é¢ä¿ãæ£å¸å³ã«æãã¦ã¿ã¾ãã
nikic/php-ast · GitHub
php-ast ã®å°å ¥
php-ast ã®å°å ¥æ¹æ³ã¯ãPHP ã®æ¡å¼µã¢ã¸ã¥ã¼ã«ãã¤ã³ã¹ãã¼ã«ããé常ã®æé ã¨åãã§ããGitHub ã®ãªãã¸ããªã clone ãã¦ãã«ããã¤ã³ã¹ãã¼ã«ããå¾ãini ãã¡ã¤ã«ãä½æãã¦æ¡å¼µã¢ã¸ã¥ã¼ã«ãæå¹ã«ãã¾ãããªããç§ã¯ anyenv ãå©ç¨ãã¦ããã®ã§æ¬¡ã®ã³ã¼ãä¾ã®ããã«ãªãã¾ããããã¡ã¤ã«ã®ç½®ãå ´æãªã©ã¯ç°å¢ã«åããã¦èªã¿æ¿ãã¦ãã ããã
$ git clone https://github.com/nikic/php-ast.git $ cd php-ast $ phpize $ ./configure $ make $ make install $ echo 'extension="ast.so"' >~/.anyenv/envs/phpenv/versions/7.0.0/etc/conf.d/ast.ini
次ã®ããã«ãã¦ãphp-ast ãæ£å¸¸ã«å°å ¥ããããã¨ã確èªã§ãã¾ãã
$ php -i | grep ^ast ast ast support => enabled
php-ast ãå°å ¥ããã¨ã次ã®ãããªç°¡åãªããã°ã©ã ã§æ½è±¡æ§ææ¨ã表示ã§ãã¾ããå é ã® require ã§ãphp-ast ã®ã½ã¼ã¹ã³ã¼ãã«å梱ããã¦ãã util.php ãã¡ã¤ã«ãè¦æ±ãã¾ã*2ãast\parse_file é¢æ°ãæ½è±¡æ§ææ¨ãçæããast_dump é¢æ°ãè¦ãããæ´å½¢ãã¦åºåãã¾ããast_dump é¢æ°ã¯ util.php ã§å®ç¾©ããã¦ãã¾ãã
<?php require __DIR__ . '/util.php'; $ast = ast\parse_file('php://stdin', $version = 15); echo ast_dump($ast) . "\n";
ãã®ããã°ã©ã ã dump.php ã¨ããã¨ãå®è¡ä¾ã¯æ¬¡ã®ããã«ãªãã¾ãã以ä¸ã¯ãtest.php ã¨ãããã¡ã¤ã«ãä½æãã¦æ½è±¡æ§ææ¨ã表示ããã¦ã¿ããã®ã§ãã
$ cat test.php <?php echo 1 + 2; $ php dump.php <test.php AST_STMT_LIST 0: AST_STMT_LIST 0: AST_ECHO 0: AST_BINARY_OP flags: BINARY_ADD (1) 0: 1 1: 2
ãã¼ãæ°ãã«ã¦ã³ãããããã°ã©ã ã®ä½æ
php-ast ã¢ã¸ã¥ã¼ã«ãå©ç¨ãã¦ãæ½è±¡æ§ææ¨ã®ãã¼ãæ°ãåºåããããã°ã©ã ãä½æãã¾ããæ½è±¡æ§ææ¨ã®ãã¼ã㯠ast\Node ã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã«ãªã£ã¦ãããchildren ãã£ã¼ã«ããåè¦ç´ ã®é åãæã£ã¦ãã¾ãããããã£ã¦ã次ã®ãããªã³ã¼ãã§ãã¼ãæ°ãã«ã¦ã³ãã§ãã¾ãããªããå ã»ã©ã® dump.php ã®åºåã§ããããããã«ãchildren ã®è¦ç´ ã¯å¿ ããã ast\Node ãªãã¸ã§ã¯ãã«ãªãããã§ã¯ãªããæ´æ°å®æ°ãªã©ã¯ç´æ¥æ ¼ç´ããã¾ããããã«å¯¾å¿ãããã children é¢æ°ãå®ç¾©ãã¦ãã¾ãã
<?php function count_node($node) { return 1 + array_sum(array_map(function ($child) { return count_node($child); }, children($node))); } function children($node) { return $node instanceof ast\Node ? $node->children : []; } $ast = ast\parse_file('php://stdin', $version = 15); echo count_node($ast) . "\n";
å ã»ã©ä½æãã test.php ã§ç¢ºèªãã¦ã¿ãã¨ã次ã®ããã« 6 ãåºåããã¾ããæ½è±¡æ§ææ¨ã®åºåã¨æ¯è¼ãã¦ã¿ãã¨ãAST_STMT_LIST ãäºã¤ãAST_ECHO, AST_BINARY_OP ã¨ç¶ããæ«ç«¯ã«æ´æ° 1, 2 ã®åè¨ 6 ãã¼ãã§ããããã«çµæãä¸è´ãã¦ãã¾ãããªããBINARY_ADD 㯠AST_BINARY_OP ãã¼ãã®å±æ§ã§ãæ½è±¡æ§ææ¨ã®ãã¼ãã§ã¯ããã¾ããã
$ php count.php <test.php 6
æ£å¸å³ã®ãããã
ããã§ã¯ãä½æããããã°ã©ã ã使ã£ã¦ããã¾ãã¾ãª PHP ãã¡ã¤ã«ã®ãã¤ãæ°ã¨ãã¼ãæ°ã®é¢ä¿ã調ã¹ã¦ã¿ã¾ããã¾ãã調æ»å¯¾è±¡ã¨ã㦠composer ã§é©å½ãªããã±ã¼ã¸ãåå¾ãã¾ããä»å㯠Symfony ã対象ã«ãã¾ãã*3ã
$ composer require symfony/symfony
åå¾ããã PHP ãã¡ã¤ã«æ°ã¯æ¬¡ã®ã¨ããã§ãããSymfony ãä¾åããããã±ã¼ã¸ã composer ã«ãã£ã¦èªåçã«åå¾ããããããsymfony ã®ä»ã«ãããã¤ãã®ããã±ã¼ã¸ãããã¾ãããã¹ã¦ã®åè¨ã¯ 3,474 ãã¡ã¤ã«ã§ããã
$ find vendor -type f -name '*.php' -print | cut -f1-2 -d/ | uniq -c 20 vendor/paragonie 6 vendor/composer 2973 vendor/symfony 9 vendor/psr 255 vendor/twig 210 vendor/doctrine 1 vendor/autoload.php
åå¾ããåãã¡ã¤ã«ã«ã¤ãã¦ããã¡ã¤ã«ãã¹ããã¤ãæ°ããã¼ãæ°ã csv å½¢å¼ã§åºåãã¾ãã確èªã®ãã head ã³ãã³ãã§å é ã® 5 è¡ã表示ãã¦ã¿ã¾ãã
$ find vendor -type f -name '*.php' -print | while read f; do echo $f,$(wc -c $f | cut -f1 -d' '),$(php count.php <$f); done >results.csv $ head -n 5 results.csv vendor/paragonie/random_compat/lib/byte_safe_strings.php,5631,321 vendor/paragonie/random_compat/lib/cast_to_int.php,2395,89 vendor/paragonie/random_compat/lib/error_polyfill.php,1533,35 vendor/paragonie/random_compat/lib/random.php,5614,308 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php,2536,116
ãã¨ã¯ãããã Excel ã§éãã¦ã°ã©ããæç»ãã¾ãã次ã®ãããªçµæã«ãªãã¾ããã横軸ããã¤ãæ°ã縦軸ããã¼ãæ°ã§ããå·¦ã¯èª¿æ»ãããã¹ã¦ã®ãã¡ã¤ã«ããããããããã®ãå³ã¯ãã¤ãæ°ã 10 kbytes ã¾ã§ã®ç¯å²ãæ¡å¤§ãããã®ã§ãã
æ£å¸å³ãçºãã¦ã¿ãã¨ãå ¨ä½çã«ã¯å½ç¶äºæ³ã§ããããã«æ¯ä¾ã®é¢ä¿ã«ãªã£ã¦ããããã§ããåç¹ã®è¿ããããè¦ãã¨ã1 kbyte ãããã§ãã¼ãæ°ã 0 è¿ãã«è½ã¡ã¦ãã¾ããã¡ã¤ã«ç¾¤ã¨ãåç¹ã«åãã£ã¦ãããã¡ã¤ã«ç¾¤ã«åãããããã«è¦ãã¾ããããã¤ãã®ãã¡ã¤ã«ã調ã¹ã¦ã¿ãã¨ãããåç¹ã«åãã£ã¦ãã群ã¯åä½ãã¹ãã®ãã¡ã¤ã«ãªã©ã§ããã¡ã¤ã«å é ã«ã©ã¤ã»ã³ã¹ã®è¨è¿°ããªããªã©ã®çç±ã§éããåºã¦ãããã®ã§ããã
*1:PHP5 ã§ã¯ãæ½è±¡æ§ææ¨ãä½ããã«æ§æ解æããªããç´æ¥ãã¤ãã³ã¼ãå½ä»¤ãçæãã¦ãã¾ããã
*2:ãã®è¨äºã§ã¯ util.php ãã¡ã¤ã«ãã³ãã¼ã㦠__DIR__ ã§æå®ãã¾ããã
*3:æè¿ã¯ä»äºã§ PHP ã使ãæ©ä¼ãå°ãªãæ å ±ã追ãã¦ããªãã£ãã®ã§ããããã¤ã®ã¾ã«ã Symfony 3.0 ããªãªã¼ã¹ããã¦ããããã§ããã¼ã¸ã§ã³ãæå®ãã require ããã¨ãã Symfony 3.0 ãå ¥ã£ã¦ãã¾ããã