PHPの構文復習

今回はPHPのクラスを書く時に登場するキーワードについてのメモ。

PHPの構文

以下より、PHPでクラスを書く時に登場するキーワードに重点を置いて説明する。

名前空間

名前空間を定義するにはnamespaceキーワードを使う。PHPでは、定義済みのクラス名、関数名、定数名は、名前の衝突が起こるので使用できないが、名前空間を使うことでこれを回避することができる。名前空間とは、OSのディレクトリに似た概念で、同じ名前でも名前空間(ディレクトリ)が違えば、使用することができる。

namespace Test;
class Directory {
    public function __construct() {
        echo 'Test\Foo\Directory', PHP_EOL;
    }
}

※PHPではJavaのようなpackageキーワードは存在しないが、Javaのpackageも結局のところ、PHPのnamespaceと同じ役割を果たしているので、ほとんど同じものと捉えてしまって問題無い。ちなみにJavaにおける「名前空間」とは概念を指していたのに対して、PHPにおける「名前空間」は機能を指すので、ここら辺がおそらく混乱を招きやすい。

名前空間を使用する

名前空間を使用するにはuseキーワードで名前空間を指定する必要がある。

include "Foo/Bar.php"; //ファイル(クラス)を読み込む
use Foo\Bar; //使用する名前空間を指定
$abc = new Bar();

外部クラスの読み込み

外部クラスを読み込むには、requireキーワード、もしくはincludeキーワードを使用する。

requireキーワード

requireを使用すれば、プログラム実行前に指定したファイルを読み込むことができる。

require "my_function.php";
$number = average(2, 4);
echo "2と4の平均は{$number}です。";

また、requireの代わりにrequire_onceを使うことで、ファイルを一度だけ読み込むことができる。

includeキーワード

includeを使用すれば、プログラム実行中に指定したファイルを読み込むことができる。

for ($count = 1; $count <= 5; $count++) {
    include "my_function" . $count . ".php";
}

また、includeの代わりにinclude_onceを使うことで、ファイルを一度だけ読み込むことができる。

クラス

クラスを定義するにはclassキーワードを使う。

class Sample {
    //何もないクラス
}

関数

関数を定義するにはfunctionキーワードを使用する。クラスにおける関数は「メソッド」と呼ばれる。

class AuthorProfile {
    public function getName(){
        return 'SmokyDog';
    }
}

変数

変数を定義するには$キーワードを使用する。$変数名 = 値;のように使用する。

$a = 1;

文字列結合

文字列結合を行うにはドット(.)を使用する。

$a = 'あいう';
$b = 123;
echo $a.$b; //あいう123 を出力
$a .= $b; echo $a; //あいう123 を出力

定数

定数を定義するには、define()関数、もしくはconstキーワードを使用する。尚、PHPの定数にはアクセス修飾子を付けることができず、必ずpublicという扱いになる。

define()関数

define()を使用すれば、グローバル定数を定義することができる。

define("CONSTANT", "Hello world.");
echo CONSTANT; // "Hello world."を出力

define()で定数を定義する場合、定数に重複する名前を付けることはできない。使い所としては、プログラムのどこからでも使用する可能性のあるものだけをこれで定数化する。(PHPファイルやディレクトリへの絶対パス、もしくは開発時と運用時の動作変更のためのフラグなど)

constキーワード

constを使用すれば、クラス定数を定義することができる。

class Animal {
    const DOG = 1;
    const CAT = 2;
}

constで定数を定義する場合、define()とは逆に、クラス内、もしくは関連性のあるクラスでのみ使用される定数を定義すべきである。

define()関数で定義された定数名を参照する時は単に定数名だけ書いてしまえばどこからでも参照可能なのに対して、constキーワードで定義された定数の場合は、 クラス名::定数名 という書き方をする必要がある。何が言いたいのかというと、define()による定義ではスコープの範囲が広すぎて、管理が難しいのだ。

アクセス修飾子

上記で出てきたpublicがアクセス修飾子にあたる。変数やメソッドのアクセス可能範囲を設定する。

アクセス修飾子 アクセス可能範囲
public クラス内、クラス外のどこからでもアクセス可能
private 同じクラス内からのみアクセス可能
protected 同じクラス、及び子クラス(継承クラス)からアクセス可能
class AuthorProfile {
    private $name = 'SmokyDog';
    public function getName(){
        return $this->name;
    }
}

静的メンバ・静的メソッド

静的メンバ・静的メソッドを定義するにはstaticキーワードを使用する。

class AuthorProfile {
    private static $name = 'SmokyDog';
    public static function getName(){
        return $this->name;
    }
}

擬似変数

上記で出てきた$thisが擬似変数にあたる。$thisはクラス自身を指す。

class SmokyDog {
    const SKILL = 'トイレで眠る';
    private $editor = 'Vim';
    public function getEditor(){
        return $this->editor;
    }
}

インスタンス

クラスのコピー(オブジェクト)を生成するにはインスタンス化を行う。new演算子を使うことで行うことができる。

class SmokyDog {
    const SKILL = 'トイレで眠る';
    private $editor = 'Vim';
    public function getEditor(){
        return $this->editor;
    }
}
$player = new SmokyDog();
$editor = $player->getEditor();
$action = $player->SKILL;

スコープ定義演算子

::(ダブルコロン)を使うことで、アクセス先を指定して変数や関数を使用できる。アクセス先にはクラス名、self、parent、staticが指定できる。
selfは自分自身、parentは親クラス、staticは直近の非転送コールを指す。staticについては理解し辛いのでまた別の記事にまとめるかもしれない。
※直近の非転送コールとは、C::foo()や$c->foo()といったクラス名(もしくはオブジェクト)を明示した呼び出しのこと。

class A {
    public static function foo() {
        B::foo();
    }
}
class B {
    public static function foo() {
        echo 'B_foo' . PHP_EOL;
    }
}
B::foo(); //foo()のスコープはC。結果:D_foo

抽象化と継承

抽象クラスと抽象メソッドを定義するにはabstractキーワードを使用する。抽象クラスはインスタンス化することができない。抽象クラスには抽象メソッドを定義することができる。

abstract class Animal {
    abstract public function action(){};
}

また、継承を行うにはextendsキーワードを使用する。

class Dog extends Animal {
    function action(){
        return 'わんわんお';
    }
}

インターフェースとその利用

インターフェースを定義するにはinterfaceキーワードを使用する。

interface Dog {
    public function setAction($action);
    public function getAction();
}

インターフェースを利用するにはimplementsキーワードを使用する。

class SmokyDog implements Dog {
    $dogAction = 'じゃれる';
    public function setAction($action){
        $this->dogAction = $action;
    }
    public function getAction(){
        return $dogAction;
    }
}

コンストラクタ

コンストラクタは__construct()関数を使用する。コードが呼び出されるとこの関数がコールされる。

class BaseClass {
    function __construct() {
        print "In BaseClass constructor\n";
    }
}

デストラクタ

デストラクタは__destruct()関数を使用する。特定のオブジェクトへの全てのリファレンスが削除された直後やオブジェクトが明示的に破棄された直後にコールされます。あるいは、スクリプトの終了時にも順不同でコールされる。

class MyDestructableClass {
    function __construct() {
        print "In constructor\n";
        $this->name = "MyDestructableClass";
    }
    function __destruct() {
        print "Destroying " . $this->name . "\n";
    }
}
$obj = new MyDestructableClass();

例外処理

例外処理を行うにはtryブロック、catchブロック、throw文を使用する。PHPの例外処理はJavaとは違い、自動で例外を投げてくれないので、PHPではthrow文をif文などと組み合わせて、自分で例外を投げる必要がある。

$a = 2;
$b = 4;
$c = 0;
echo "--- Exception Test ---\n\n";
try {
    echo "****** Begin try ******\n\n";
    if($a == 0) {
        throw new Exception("ゼロ除算なのでエラーです。");
    }
    //割り算する
    $c = $b / $a;
    echo "****** End try ******\n\n";
} catch(Exception $e) {
    echo "****** catch ******\n\n";
    echo '$e->getMessage() : ', $e->getMessage(), "\n\n";
    echo "\$e : \n", $e, "\n\n";
}
echo "--- Exception Test ---"; ?>

また、以下のようにして独自に例外クラスを定義してエラー内容を細分化することもできる。

class A_exception extends Exception {
    function __construct() {
        __parent("A error");
    }
}
class B_exception extends Exception {
    function __construct() {
        __parent("B error");
    }
}
function A_sample($a){
    if($a == 0){
        throw new A_exception();
    }
}
function B_sample($b){
    if($a == 0){
        throw new B_exception();
    }
}
try {
    A_sample(1); //1を渡すのでエラーにはならない
    B_sample(0); //0を渡したのでエラーとなる
} catch (A_exception $e) {
    echo "Aエラー";
} catch (B_exception $e){
    echo "Bエラー";
} catch (Exception $e) {
    echo "その他のエラー";
}

上記では”Bエラー”が出力される。
※PHP5.5以降ではfinallyブロックも使用可能。

参考
PHP: PHP マニュアル – Manual
デストラクタがコールされるタイミング【php】
PHPを愛する試み ~self:: parent:: static:: および遅延静的束縛~ – maeharinの日記