三陸牡蠣復興支援プロジェクト「SAVE SANRIKU OYSTER」



演算子

演算子(オペレーター)とは

演算子(オペレーター)」は、『演算の対象となる「被演算子(オペランド)」(関数の引数に当たるもの)を評価(計算する事)し、その結果を返す』という処理を行うものです。既に何度も登場している「代入演算子」の例で説明すると、「$hode = "HODENASU";」という一文の場合、演算子は真ん中の「=(イコール)」で、演算の対象となる被演算子は左辺の「変数$hode」と右辺の「"HODENASU"」という文字列です。

今回の「代入演算子」が行う処理は、「左辺(第1オペランド)の“値を格納できるもの(変数)”に右辺(第2オペランド)の値を代入し、代入した値を返す」というものです。これを踏まえて以下のサンプルと結果をご覧下さい。

<html>
<body>
<?php
    $nasu = $hode = "HODENASU";
    echo $hode."<hr />";
    echo $nasu;
?>
</body>
</html>
HODENASU

HODENASU

$nasu = $hode = "HODENASU";」の部分で行われている事を説明すると、まず「$hode = "HODENASU";」の部分が処理され、代入演算子は結果として代入した値を返します。するとこの部分は文字列の「"HODENASU"」になり、更にまたもう1つの代入演算子によって、「$nasu = "HODENASU";」が処理されます。

代入演算子は、1箇所に複数あった場合、右側から処理します。もし逆だと、値に値を代入する事になってしまうからです。

演算子の種類

PHPで使える演算子は約50個あり、次の11種類に分類されます。

  • 代数演算子
  • 文字列演算子
  • 代入演算子
  • 加算子/減算子
  • 配列演算子
  • 比較演算子
  • 条件演算子
  • 論理演算子
  • エラー制御演算子
  • ビット演算子
  • 実行演算子

また、各演算子はそれぞれ演算対象、要するにオペランド(被演算子)の数が決まっていて、その数によって、オペランドが1つの場合は「単項演算子」、2つの場合は「2項演算子」、3つの場合は「3項演算子」と呼びます。既に登場した代入演算子はオペランドが2つなので2項演算子です。

代数演算子(算術演算子)

代数演算子(算術演算子)」は、「足し算」や「引き算」を行う演算子です。代数演算子には次の5つがあります。

記述名前処理・返り値
$a + $b加算演算子両オペランドを加算した値を返す
$a - $b減算演算子左辺と右辺の差を返す
$a * $b乗算演算子左辺と右辺の積を返す
$a / $b割算演算子左辺と右辺の商を返す
$a % $b剰余演算子左辺を右辺で割った余りを返す

文字列演算子

文字列演算子」は、「文字列の連結」を行う演算子です。文字列演算子には次の2つがあります。

記述名前処理・返り値
"hode" . "nasu"結合演算子両オペランドを連結した文字列を返す
$hode .= "nasu"結合代入演算子$hode = $hode ."nasu"」の省略形

代入演算子

代入演算子」は、「左辺の“値を格納できるもの(変数)”に右辺の値を代入し、代入した値を返す」という処理をする演算子です。代入演算子の基本となるものは「=(イコール)」(「基本代入演算子」)で、これに加えて、この「=(イコール)」の左側に代数演算子や文字列演算子などを合体させた「複合演算子」があります。

記述名前処理・返り値
$a = $b基本代入演算子左辺(変数)に右辺の値を代入し、代入した値を返す
$hode .= "nasu" 等複合演算子$hode = $hode ."nasu"」の省略形

複合演算子
+= -= *= /= %= &= |= ^= ~= <<= >>=

加算子/減算子

加算子/減算子」は、被演算子の値を「1」だけ増減(インクリメント/デクリメント)させる演算子です。次の4つがあります。

記述名前処理・返り値
++$a前置加算子$a」に「1」を足して、その結果を返す
$a++後置加算子$a」の値を返し、「$a」に「1」を足す
--$a前置減算子$a」から「1」を引いて、その結果を返す
$a--後置減算子$a」の値を返し、「$a」から「1」を引く

ちょっと解かり辛いので以下のサンプルと結果をご覧下さい。

<html>
<body>
<?php
    $a = $b = $c = $d = 5;
    
    echo ++$a;
    echo "<hr />";
    echo $a;
    echo "<hr />";
    
    echo $b++;
    echo "<hr />";
    echo $b;
    echo "<hr />";
    
    echo --$c;
    echo "<hr />";
    echo $c;
    echo "<hr />";
    
    echo $d--;
    echo "<hr />";
    echo $d;
?>
</body>
</html>
6

6
5
6
4
4
5
4

++$a」と「--$a」の「前置型」はそれぞれ、「$a += 1」と「$a -= 1」の省略形です。

では、「$a++」と「$a--」の「後置型」はというと、増減処理の前に値を返しています。返してから、増減処理しています。値を返した時点で処理を終える関数ではあり得ない処理ですね。

配列演算子

配列演算子」は、「左辺の配列に右辺の配列を追加する(ただし、重複するキーは上書きしない)」という処理を行う演算子です。

記述名前処理・返り値
$arr1 + $arr2配列演算子配列「$arr1」に配列「$arr1」のキーが重複しない要素を追加。
その結果できた配列を返す

代数演算子の「+(プラス)」(加算演算子)は、被演算子が配列の場合、配列演算子として機能します。以下のサンプルと結果をご覧下さい。

<html>
<body>
<p>
<?php
    $arr1 = array( "dog" => "wan",
                   "cat" => "nyan",
                   "cow" => "mou" );
    
    $arr2 = array( "dog"   => "wan",
                   "cow"   => "mou",
                   "frog"  => "gero",
                   "mouse" => "chu" );
    
    $arr = $arr1 + $arr2;
    
    print_r($arr1);
    print_r($arr2);
    print_r($arr);
?>
</p>
</body>
</html>
Array([dog] => wan [cat] => nyan [cow] => mou)Array(...

これだと見辛いので、HTMLのソースを見てみます(もしくは「<pre></pre>」タグで括る)。すると以下の様にきれいに改行・インデントされているので見やすくなります。

<html>
<body>
<p>
Array
(
    [dog] => wan
    [cat] => nyan
    [cow] => mou
)
Array
(
    [dog] => wan
    [cow] => mou
    [frog] => gero
    [mouse] => chu
)
Array
(
    [dog] => wan
    [cat] => nyan
    [cow] => mou
    [frog] => gero
    [mouse] => chu
)
</p>
</body>
</html>

まず、「print_r」は、「配列の中身を展開して出力する」という処理を行う関数です。

結果を見ると、結合して生成された配列「$arr」は、配列「$arr1」に配列「$arr2」の、キーが重複しない要素のみが追加されたものになっています。

比較演算子

比較演算子」は、「左辺の値を右辺の値と比較してどうかを、その結果に応じた真偽値を返す」という処理を行う演算子です。次の9つがあります。

記述比較返り値
$a == $b等しい結果に応じた真偽値
$a === $b等しい(型も同じ)結果に応じた真偽値
$a != $b等しくない結果に応じた真偽値
$a <> $b等しくない(「!=」と同じ意味)結果に応じた真偽値
$a !== $b等しくない、値は等しくても型が違う結果に応じた真偽値
$a < $bより少ない結果に応じた真偽値
$a > $bより多い結果に応じた真偽値
$a <= $bより少ないか等しい結果に応じた真偽値
$a => $bより多いか等しい結果に応じた真偽値

以下のサンプルと結果をご覧下さい。

<html>
<body>
<p>
<?php
    $a = 5;
    $b = "5";
    
    if($a === $b){
        echo '$a === $b';
    }else if($a == $b){
        echo '$a == $b';
    }else{
        echo '$a != $b';
    }
    
    echo "<hr />";
    
    if("HODENASU" == 0){
        echo '"HODENASU" == 0';
    }else{
        echo '"HODENASU" != 0';
    }
?>
</p>
</body>
</html>
$a == $b

"HODENASU" == 0

今回のサンプルでは、「変数$a」と「変数$b」は、値は同じですが型が異なるのでこの様な結果になりました。

ついでに、文字列の「"HODENASU"」と数値の「0」を「==」で比較した所、何と、どういう訳か、“等価である”と評価されました。これは本家のマニュアルの「付録」セクションの「PHP 型の比較表」のページに明記されたPHPの仕様という悲しい事実なので受け入れるしかありません。例えば連想配列の添え字を取り出してその中に特定の文字列があるかどうか調べたいなんて時に「if(配列の添え字を取り出して格納した変数 == 存在するか調べたい文字列の添え字){echo "OK!";}」を実行すると、存在しない場合には「OK!」と出力される事はありませんが、配列の中に数値の「0」を添え字にした要素が存在すると、そこで「OK!」を出力する事になります。この奇想天外な仕様のお陰でハマリました。こういう時は「if(配列の添え字を取り出して格納した変数 === 存在するか調べたい文字列の添え字){echo "OK!";}」の様に「===」で比較するようにしなくてはなりません。ちなみに他の言語はどうか知りませんが、JavaScriptでは「"HODENASU"」と「0」は普通に等価ではありません。

条件演算子

条件演算子」は、「一番左側から順に、第一オペランドが真なら第二オペランドの、偽なら第三オペランドの値を返す」という処理を行う、唯一の3項演算子です。

記述処理・返り値
$a ? $b : $c$a」が「真」なら「$b」を、「偽」なら「$c」を返す

以下のサンプルと結果をご覧下さい。

<html>
<body>
<p>
<?php
    echo "HODE" == "NASU" ? "TRUE" : "FALSE";
?>
</p>
</body>
</html>
FALSE

今回のサンプルでは、「"HODE" == "NASU"」の評価は偽で、条件演算子にとっての第一オペランドの値は偽である為、第三オペランドの「"FALSE"」が出力されました。

ちなみに、後述しますが、今回のサンプルで条件演算子が評価される前に比較演算子が評価されたのは、条件演算子よりも比較演算子の方が優先順位が高いからです。

論理演算子

論理演算子」は、「真偽値の比較」を行う演算子です。次の6つがあります。

記述名前処理・返り値
$a and $b論理積両オペランドが「真」なら「true」を返す
$a or $b論理和いずれかのオペランドが「真」なら「true」を返す
$a xor $b排他的論理和両オペランドの真偽値が異なれば「true」を返す
!$a否定オペランドが「偽」なら「true」を返す
$a && $b論理積両オペランドが「真」なら「true」を返す
$a || $b論理和いずれかのオペランドが「真」なら「true」を返す

「論理積」と「論理和」の演算子が2通りあるのは、演算の際の優先順位(後で解説)が異なるためです。「&&」、「||」は、「and」、「or」よりも優先順位が高いです。そして、代入演算子と比較演算子の優先順位がこの2つの優先順位の間に来ます。つまり、「&&」と「||」、「=」や「==」、「and」と「or」の順に優先順位が高いという事です。優先順位が高いほど先に演算されます。が、これ(優先順位)については後で解説。

また、論理演算子の特性として、「論理積」の場合は、「左辺が真でかつ右辺が真なら真を返す」というものなので、もし左辺が偽ならその時点で偽であるため、右辺を評価(計算)する必要が無くなり、評価しないで結果を返します。また「論理積」の場合は、「左辺もしくは右辺が真なら真を返す」というものなので、もし左辺が真ならその時点で真であるため、右辺を評価する必要がなくなり、評価しないで結果を返します。これを踏まえた上で以下のサンプルと結果をご覧下さい。

<html>
<body>
<p>
<?php
    $a = "dog";
    $b = "";
    
    if( ($a == "dog") and ($b = "cat") ){
        
    }
    
    echo '$a : '.$a."<br />";
    echo '$b : '.$b."<br />";
    
    echo "<hr />";
    
    $a = "dog";
    $b = "";
    
    if( ($a == "dog") or ($b = "cat") ){
        
    }
    
    echo '$a : '.$a."<br />";
    echo '$b : '.$b."<br />";
    
    echo "<hr />";
    
    $a = "dog";
    $b = "";
    
    if( !$b ){
        $b = "cat";
    }
    
    echo '$a : '.$a."<br />";
    echo '$b : '.$b."<br />";
    
    echo "<hr />";
    
    $a = "dog";
    $b = "";
    
    if( ($a == "dog") xor ($b == "") ){
        $b = "cat";
    }
    
    echo '$a : '.$a."<br />";
    echo '$b : '.$b;
?>
</p>
</body>
</html>
$a : dog
$b : cat

$a : dog $b :
$a : dog $b : cat
$a : dog $b :

今回のサンプルは、『「変数$a」に「"dog"」を、「変数$b」に「""」をセットし、「if文」を通過した後、それぞれ出力する』という処理を4パターンの条件式で行っています。

1つ目の「if文」の条件式「($a == "dog") and ($b = "cat")」では、まず「$a == "dog"」の真偽が「真」と評価され、次に「$b = "cat"」が評価されます(「変数$b」に「"cat"」が代入される)。

2つ目の「if文」の条件式「($a == "dog") or ($b = "cat")」では、まず「$a == "dog"」の真偽が「真」と評価され、この時点で「真」が確定され次の真偽判定の必要がなくなり、「$b = "cat"」は評価されません。

3つ目の「if文」の条件式「!$b」では、まず「$b」の真偽が「偽」と評価され(空文字列なので)、その「否定」の「真」と判定されます。よって、「$b = "cat"」は評価されます。

4つ目の「if文」の条件式「($a == "dog") xor ($b == "")」では、「$a == "dog"」と「$b == ""」が両方とも「真」であるため、「偽」と判定されます。よって、「$b = "cat"」は評価されません。

エラー制御演算子

エラー制御演算子」「@(アットマーク)」は、「何らかの問題で生成されたエラーメッセージを無視する(出力を行わない)」という働きを持った演算子です。

記述名前処理
@func()@$hodeエラー制御演算子生成されたエラーメッセージを出力しない

エラー制御演算子は、「式(値を持つもので、「変数」や「定数」、そして「関数」の事)」でのみ動作します。また、文法ミスによるエラーメッセージは制御出来ません。以下のサンプルと結果をご覧下さい。

<?php
    @func();
?>
(何も出力するものがありません)
<?php
    @func()
    @func();
?>
(文法ミスによるエラーメッセージ)

今回のサンプルでは、エラー制御演算子によって、本来出力されるはずの「未定義の関数を呼び出しています」旨のエラーメッセージが出力されていません。文法ミスによるエラーメッセージは出力されました(文法ミスは演算子が使用される以前の問題である為)。

ビット演算子

ビット演算子」は、「整数をビット単位で演算する」という働きを持った演算子です。次の6つがあります。

記述名前処理・返り値
$a & $bビット積$a」と「$b」の両方にセットされているビット
$a | $bビット和$a」と「$b」のどちらかにセットされているビット
$a ^ $b排他的論理和$a」と「$b」の片方のみにセットされているビット
~$a否定$a」のビットを反転させる
$a << $b左シフト$a」のビットを左に「$b」ビット分シフト(移動)する
シフト毎に「2」を掛けた事になる
$a >> $b右シフト$a」のビットを右に「$b」ビット分シフト(移動)する
シフト毎に「2」で割った事になる

以下のサンプルと結果をご覧下さい。

<?php
    $a = 35;
    $b = 3;
    
    echo $a & $b; 
    
    echo "<hr />";
    
    echo $a | $b; 
    
    echo "<hr />";
    
    echo $a ^ $b; 
    
    echo "<hr />";
    
    echo ~$a; 
    
    echo "<hr />";
    
    echo $a << $b; 
    
    echo "<hr />";
    
    echo $a >> $b; 
?>
3

35
32
-36
280
4

今回のサンプルでは、まず「変数$a」と「変数$b」にそれぞれ「35」と「3」をセットし、ビットごと演算を行って出力しています。

ビットごと演算するには、まず整数をビット(つまり2進数表記)に変換します。すると、「35」と「3」はそれぞれ「100011」と「11」に表されます。この2つを元に演算していきます。

1つ目の「$a & $b」は、「100011」と「000011」の両方にセットされているビット、つまり「11」を、10進表記に戻すと「3」を返します。

1つ目の「$a | $b」は、「100011」と「000011」のどちらかにセットされているビット、つまり「100011」を、10進表記に戻すと「35」を返します。

1つ目の「$a ^ $b」は、「100011」と「000011」の片方のみにセットされているビット、つまり「100000」を、10進表記に戻すと「32」を返します。

1つ目の「~$a」は、「100011」ビットを反転したビット、つまり「011100」を…(ここがどうなってるのか解からない)…、10進表記に戻すと「-36」を返します(汗)。

1つ目の「$a << $b」は、「100011」を左に「3」ビット分シフトさせたビット、つまり「100011000」を、10進表記に戻すと「280」を返します。左にビットシフトするということは、ようするに「桁上がり」するという事で、2進数の基数は「2」なので、10進数が10倍するごとに桁上がりする様に、2進数は2倍するごとに桁上がりします。よって、左に1シフトする事は2倍するのと同じ事なのです。

1つ目の「$a >> $b」は、「100011」を右に「3」ビット分シフトさせたビット、つまり「100」を、10進表記に戻すと「4」を返します。

実行演算子

演算子のラストは「実行演算子」「`(後方引用符、バッククォート)」です。この演算子は、「パラメータをシェルコマンドとして実行しようとし、その出力を返す」という働きを持った演算子です。

記述名前処理
`ls -al`実行演算子シェルコマンドの実行、その出力を返す

はっきり言って、理解しておりません(オイ)。この演算子を使うには条件が整っている必要があったり、また「シェル」というものを理解している必要があります。このページの範囲を超えるので、実行演算子についての解説はこれでおしまいにします。

演算子の、結合時の評価と優先順位

演算子は、例えば「$a = $b = $c 」の場合、まず「$b = $c 」が評価され、次に「$a = 結果の値 」が評価されます。この様に、1つの式に複数結合した演算子がある場合、演算子の種類によって、どちら側から評価していくのかが決まっています。また、それぞれの演算子には優先順位というものがあって、違った種類の演算子が混在する場合は、優先順位の高いものから先に演算されます。

演算子の結合時の評価の向き(どちら側から評価するのか)と優先順位は次の通り(優先順位が高い順)です。

結合時の評価の方向 演算子
結合しない new
[
! ~ ++ --
(int) (double) (string) (array) (object)
@
* / %
+ - .
<< >>
結合しない < <= > >=
結合しない == != === !==
&
^
|
&&
||
? :
= += -= *= /= .= %= &= |= ^= ~= <<= >>=
print
and
xor
or
,
結合時の評価の方向について
  • 「結合しない」とは、例えば「$a == $b == $c」の様な書き方は許されていない事を意味します。このような場合は、「$a == $b and $b == $c」や「$a == $b and $a == $c」という形で書きます。
  • 「右」は、例えば「$a = $b = $c」という式の場合、右側の「$b = $c」を先に評価する事を意味します。
  • 「左」は、例えば「$a + $b - $c」という式の場合、左側の「$a + $b」を先に評価する事を意味します。
優先順位について
  • 異なる種類の演算子が混在している場合、優先順位が高い方の演算子から評価を行います。例えば「$a + $b * $c」という式の場合、「+」と「*」では「*」の方が優先順位が高いため、「$b * $c」の部分が先に評価されます。
  • 優先順位を強制的に最優先にさせたい場合は、優先させたい個所を「()(丸括弧)」で括ります。例えば「($a + $b) * $c」とすれば、先に「$a + $b」の部分が評価されます。

おさらいと予告

これにて、演算子の解説は終わりです。

演算子とは

  • 演算子(オペレーター)は、与えられた被演算子(オペランド)を処理し、結果の値を返す。
  • 演算子には、「代数演算子」、「文字列演算子」、「代入演算子」、「加算子/減算子」、「配列演算子」、「比較演算子」、「条件演算子」、「論理演算子」、「エラー制御演算子」、「ビット演算子」、「実行演算子」の11種類があり、さらにこれらの中に幾つもの演算子がある。また、被演算子の数によって「単項演算子」、「2項演算子」、「3項演算子」と呼ぶ。
  • 演算子には評価をする順番(左右どちら側から評価するか)と、種類ごとに優先順位があり、優先順位が高い方の演算子から評価される。
  • 強制的に評価を優先させたい場合は、その個所を「()(丸括弧)」で括る。

クラスとオブジェクト

次回は、「オブジェクト型」を理解するための、「クラス」と「オブジェクト」について解説します。オブジェクトは配列同様、複合型の値です。配列が複数の値を保持するのに対して、オブジェクトは『「メンバ変数(プロパティ)」という値と「メンバ関数(メソッド)」という関数を保持する』という構造をしています。このオブジェクトの構造を定義するものがクラスです。

作成日:2004年05月16日 最終更新日:2004年05月19日
【印刷モード風モード で表示】