静的メンバ

静的メンバとは

クラスのメンバへのアクセスはインスタンスを生成しなければ出来ませんでした。

しかしインスタンスを生成しなくてもアクセス可能なメンバも作れます。
これを「静的(スタティック)メンバ」と呼んでいます。

まずは例を見てください。

<?php

class PriceFormater
{
    public static function formatJapanese($price)
    {
        $price = number_format($price);
        $price = $price . '円';
        return $price;
    }    

    public static function formatBasic($price)
    {
        $price = number_format($price);
        $price = '\' . $price;
        return $price;
    }
}

$price = PriceFormatter::formatBasic(2000);
echo $price;

$price = PriceFormatter::formatJapanese(3000);
echo $price;

?>
string(8) "\2,000"
string(8) "3,000円"

普通のメソッドとは違い、「static」というキーワードが付いています。

これも修飾子の一つです。staticをつけたメソッドはインスタンスを生成しなくても直接「クラス名::メソッド名()」で呼び出します。

フィールドも同じです。
例えば「public static $aaa;」という感じで定義したフィールドは、
クラス名::$フィールド名」で直接参照が可能です。

そしてもちろん、クラスの外より呼び出すわけですからアクセス修飾子は「public」の場合に限ります。

クラス内よりアクセスする場合は、
「self::$フィールド名」「self::メソッド名()」となります。

逆にstaticメソッドはインスタンスよりの呼び出しは出来ません

静的メンバの考え方

通常のメンバはインスタンスに属します。
なので同じクラスをもとにしていても、別々のインスタンスであれば保持する値はそれぞれ別々です。

メソッドもインスタンスに属するメソッドと考えます。メソッドは基本的にはフィールドに対するアクセサと考えることも出来ます。フィールドに値をセットする、フィールドの値を加工して返す、という感じです。

対して静的メンバはクラスそのものに属します
そのためインスタンスメンバとは基本的には直接の関わりがありません。
静的メンバとインスタンスメンバの間には関係がないのです。

分かりにくいかもしれませんが、要はフィールドの値に絡む処理であるかどうか、というところです。
別に絡まなくてもインスタンスのメソッドでも全然問題ないのですが、絡まないならstaticでもいい、ということです。

オブジェクト指向の最大の特徴はインスタンスの性質にあります。
なので、インスタンスの特性とは関係のない静的メソッドは、ほとんど関数と同じような扱いです。クラスのメソッドではなくて普通の関数ありますよね。
あれは引数を受け取って、加工して返す、という感じの役割を果たしていると思います。

まさにそんな感じのものです。

なので例えば計算処理クラスとか言うのを作ったとしたら、
メソッドは全部staticになるんじゃないでしょうか。

<?php

class Calculator
{
    // 足し算
    public static function addition($int1, $int2)
    {
        return $int1 + $int2;
    } 

    // 引き算 
    public static function substraction($int1, $int2)
    {
        return $int1 - $int2;
    } 

    // 平均値を求める
    public static function getAverage($intVals)
    {
        if (false == is_array($intVals)) {
            return false;
        }
        $cnt = count($intVals);
        $total = 0;
        foreach ($intVals as $int) {
            $total += $int;
        }
        $average = $total / $cnt;
        return $average;
    } 
}

$answer = Calculator::addition(10, 1);
var_dump($answer);

$answer = Calculator::substraction(10, 1);
var_dump($answer);

$intVals = array(1, 2, 3, 4, 5, 6, 7);
$answer = Calculator::getAverage($intVals);
var_dump($answer);

?>
int(11)
int(9)
int(4)

計算クラスっていうのはメソッドごとに受け取った引数の計算結果を返すという、処理がメソッドだけで完結するものです。つまり、フィールドを必要としません。
極端な話、これらはクラスである必要もありません。それぞれ、ただの関数で定義しても実質の違いはありません。

もちろん設計によりますが、こういったユーティリティ的なクラスは静的メソッドが多くなる傾向にあります。別にスタティックにしなくて、インスタンスを生成してもいいですが、メリットはありません。そうであるならばスタティックの方が気軽に利用できます。
以下のようなクラスも考えられます。

<?php

class String
{
    // 文字列分割
    public static function split($splitter, $string)
    {
        return explode($splitter, $string);
    }

    // 配列結合
    public static function join($glue, $array)
    {
        if (false == is_array($array)) {
            throw new Exception("結合対象が配列ではありません");
        }
        return implode($glue, $array);
    }

    // 文字切り出し
    public static function substring($string, $start, $length = null)
    {
        if (null == $length) {
            return substr($string, $start);
        } else {
            return substr($string, $start, $length);
        }
    } 
}

?>

「String」クラスと称して、文字列操作クラスを作成しました。
といっても、見たとおり各メソッドは、同じ動きをするPHPの標準関数を実行して結果を返しているだけです。

意味は薄いですが、関数を直接呼び出すってのはオブジェクト指向的ではないため、あえてクラスの中に関数を閉じ込めてみました。しかし、文字列操作の関数を集めてStringクラスを作っているので、文字列処理として関数をパッケージングしていることになります。

こういうクラスをラッパークラスなんて呼んだりします。
元々存在する、標準関数などの処理をクラスの中に包み込み(ラッピング)、より分かりやすく、より便利な形で提供するクラスです。

上の例は文字列操作系の関数をいくつかラッピングしていますが、単に標準関数を呼び出だすだけでは芸がないので、ある程度のチェックロジックを入れました。

まあ標準関数なんて無数にあるのでやりだしたらキリがないのでこういうことはあまりやりませんけどね。
静的メソッドの例としてみてください。

静的メンバが力を発揮する場面

静的メンバが威力を発揮する場面があります。
それは「シングルトン」と呼ばれる実装方法です。かなり実践的でトリッキーな仕組みなので、とりあえずは知らなくても全然大丈夫です。ひとつの手法の紹介というレベルで見てください。

シングルトンとは、アプリケーションの処理全体を通して、あるクラスのインスタンスは絶対に1つしか存在しない事を保証する仕組みです。

これを実現するには以下のようにします。

<?php

class SingletonSample
{
    private static $instance;

    private function __construct()
    {

    }

    public static function getInstance()
    {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

$ins1 = SingletonSample::getInstance();
$ins2 = SingletonSample::getInstance();
if ($ins1 === $ins2) {
    echo '同一インスタンスです';
} else {
    echo '違うインスタンスです';
}

?>

解説しましょう。

まずこのクラスはコンストラクタがprivateになっています。つまり、外部からはnewによるインスタンス生成が出来ません。
ではどうするのかというと、静的メソッドであるgetInstanceメソッドです。このメソッドの中では自分自身のインスタンスをnewで生成しています。クラス内なのでnewが可能なわけです。そして自分自身のクラスの静的フィールドである$instanceにそれを格納しています。
以降、getInstanceメソッドを再度呼び出しても、newは通らず、既に生成されて$instanceに格納されているインスタンスを返すだけの仕組みです。
そして外側からのインスタンス生成にはgetInstanceを通すしかありません。つまり、newは絶対に一度しか行われないわけです。

これの何が嬉しいかは詳しい説明は省きますが、「シングルトン」でググって調べてみてください。