細かいことが気になり出すと、調べ尽くして解答を出すまで次の事に移れないタイプで。
PHPを覚えたての頃、標準出力にテキストや変数などを書き出す際に使う命令、echoとprintがあるということを学んだ。そして、解説書に書いてある通り、これらの命令はそれほど違わないので好きな方を使えば良いと理解した。
たまたまPHPにおける三項演算子を調べていたとき、echoとprintで挙動が異なるという例に当たった。三項演算子については、まとめ直した投稿をそのうち上げる予定だけれど、”?”や”:”といった演算子で挟まれる部分は、式でなければならないらしい。そして、echoなどは式という条件を満たさない言語構造であるから、入れるとエラーが出ますよ。ちなみにprintも言語構造ですよ。でも、関数のように振る舞うからエラーが出ませんよ。といったよく分からない説明があった。
//エラーにならない(理由:式だから) $alcohol = $age >= 20 ? "OK" : "NG"; echo $alcohol; //エラーにならない(理由:式だから) $age >= 20 ? $alcohol = "OK" : $alcohol = "NG"; echo $alcohol; //エラーにならない(理由:式だから) $alcohol = $age >= 20 ? htmlentities("OK") : htmlentities("NG"); echo $alcohol; //エラーになる(理由:言語構造だから) $age >= 20 ? echo "OK" : echo "NG"; //エラーにならない(理由:言語構造だけど関数のように振る舞うから) $age >= 20 ? print "OK" : print "NG"; |
PHPの式とはなんだろう?
上の3つの例でエラーにならないのは、三項演算子の書式(式1)?(式2):(式3);これに即しているため。ではそもそもPHPにおける式の定義とは何だろうか。マニュアルを見るとちゃんと一項目があって、式とは値があるものだそうです。
一番上の例、”OK”や”NG”というのは、値である。これはとても直感的にわかる。
上から2番目は代入式だ。ここで結構ショッキングな事実になるけれども、実は代入式では、左辺の$alcoholに右辺の値”OK”が代入されるのみならず、式自体も右辺と同じ値を持つということらしい。
したがって、代入式は値を持っているのでエラーにならない。
上から3番目。関数を呼んで実行するのも式だ。htmlentities関数はstring型を返り値として返す。また、特に値を返す設定をしていない関数(たとえば、ユーザ定義関数でreturnを行わないタイプ)でも、自動的にNULLを返す設定となっている。つまり値を返すから式だ。
言語構造とは
では、関数ではない言語構造と呼ばれるものは一体なんなのだろう。言語構造(Language Constructs)とは、英語で見れば何のこともない。言語を構成する要素である。ifとかwhileとかといったものと同じ。制御構造を作るためのifやwhileとともに、言語に最初から存在するものとしてハードコードされているため、関数のように決まった形でないと呼び出せないというような制約はない。echoはecho “文字列”;のようにもecho(“文字列”);と関数のようにも呼び出せるが、これは便宜のためたまたまどちらの書き方でも呼び出せるようにハードコードされているからで、echoの属する言語構造というカテゴリがこうした文法的制約を持っているわけではない。
関数ではないということで、当然のことながらcall_user_func(“echo”,”文字列”);こういった呼び出し方も出来ない。
echoとprintの違いとは
では、echoとprintが両方とも言語構造でありながら、異なるというところはどこだろうか。実は先程echoが便宜のため関数のように括弧を付けても呼び出せると書いたが、printはさらに返り値として常に1を返してくる。つまり、printの方が関数への擬態がうまい。そしてその分処理が重い。
そして、何らかの値を返すということは、printは式になるのである。そのため、三項演算子の中の式としても使えていたのである。
なるほどよく分かった。ちなみに違いとしてもう一つ、echoはecho”値1″,”値2″;のように使う事も出来るというものがあり、大抵の解説書にはechoとprintの違いとしてこちらが説明されているのではないかと思う。そっちの方が重要かもしれないね。
関数っぽいけど言語構造のもの一覧
最後に、一見関数のように見えて実は言語構造という例をいくつか挙げておこう。
返り値の型 | 名前 | 機能 |
---|---|---|
なし | echo | 文字列を出力 |
int | 文字列を出力 | |
array | array | 配列を生成 |
array | list | 配列の形式で、変数に値を代入 |
mixed | eval | 文字列をPHPコードとして評価 |
なし | unset | 変数を破棄する |
bool | isset | 変数がセットされているか調べる |
bool | empty | 変数が空かどうか調べる |
なし | exit | スクリプトの実行を終了 |
なし | die | exitと同等 |
mixed | include | ファイルを読み込む |
mixed | require | ファイルを読み込む(読み込めないと停止) |
同列に扱っているけど、既に説明したとおり共通した呼び出し方の制約はない。フリーダムなやつらなので注意が必要。