読者です 読者をやめる 読者になる 読者になる

DT日記

家を離れた自宅警備員の日記

2016年8月23〜25日の日記

1

日記を習慣にしようと思ったけど数日置いてしまって後でまとめる現象。

むかしはてなダイアリーってサイトでやったわー。そのうち追従できなくなるやつ。

2

先週Flycheckに送ってたプルリックだけど、そろそろまとまるかな。

github.com

機械翻訳頼りの怪しい英語でしか情報を残しておかないのはどうかと思ふので、日本語でも書いておくね。

FlycheckってのはEmacs向けのシンタックスチェッカーのコレクションで、GNU Emacs標準添付とかじゃないんだけど、これだけ入れておけばいい感じに文法違反をチェックしてくれるやつね。

PHPやってると、趣味でも仕事でもPHPスクリプトを書きたくなることって、よくあるじゃないですか。ここではshebang)がついて、コマンドラインから起動されることを意図したPHPスクリプトのことです。

さて、モダンPHPnamespaceを持つものです。以下のようなhello.phpがあったとしますね。

#!/usr/bin/env php
<?php

namespace Flycheck\Sample;

echo "Hello", PHP_EOL;

このスクリプトは文法違反ではありません。特定の文脈では。

PHPコマンドには文法チェッカが含まれて居り、php -lでSyntax errorがないか確認することができます。php -l hello.phpで文法チェックをすると、文法違反のスクリプトではないことがわかります。

しかし不思議なことに、Flycheckを通すとこのスクリプトはSyntax errorだと警告を受けることになります。

f:id:zonu_exe:20160827013625p:plain

それはなぜか。

@tadsanは終始てきとーな言動しかしないのでPHPは制禦構造を持ったテンプレートエンジンだとかPHPはテンプレートエンジンじゃない。調子に乗るなとか雑に言ったりするんですけど、この問題はまさにPHPの両面性を示したものです。

本来のPHPは、みなさまがよく御存じの通りWebページを作成するためのテンプレートエンジンのような言語です。

<p>今日は<?= date('Y年m月d日') ?>です。</p>

これは文法的には以下のスクリプトとおよそ等価です。

<?php
echo '<p>今日は';
echo date('Y年m月d日');
echo 'です。</p>', PHP_EOL;

ここでふと疑問がよぎります。

#!/usr/bin/env php
<?php

これは echo '#!/usr/bin/env php', PHP_EOL; と等価ではないか、と。

% ./hello.php
Hello
% php ./hello.php
Hello
% php -e < ./hello.php
PHP Fatal error:  Namespace declaration statement has to be the very first statement or after any declare call in the script in - on line 4

Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in - on line 4

おやおや、これは不穏……! Fatal errorになっちゃった。

hello.phpからnamespaceの含まれた行だけを抜いたhello2.phpを作ってみますね。

% php -e < ./hello2.php
#!/usr/bin/env php
Hello

ビンゴ! #!/usr/bin/env phpも標準出力されてきました。つまり、 echo '#!/usr/bin/env php', PHP_EOL; と等価だ。「まじかよ」と思ったら疑念を放置せず、自分の環境で動かしてみてくださいよ。

ここから導きだされる結論は「PHPCLIでファイルを直接実行する場合だけshebangを無視する」です。php -e、つまり標準入力からスクリプトを読み込んだ場合は対象になりません。この現象自体はよく知られたもので、shebangのついたファイルをinclude/requireしたときにはshebangが標準出力される羽目になります。

さて、namespacePHPスクリプトファイル内の最初(ただしdeclareを除く)に書かなければいけないので、echo '#!/usr/bin/env php';に相当する文が存在するとこのルールに違反し、Fatal errorになるわけです。

3

話が長くなったので節を分けますが、これを回避するための結論は「文法チェック時には標準入力は利用せずファイルを利用する」です。

4

qiita.com

5

木曜はnomikai.elと称して、Emacsっぽいひとたちと飲んだ。

6

EmacsM-x はコマンドパレットだ!!