pirosikick's diary

君のハートにunshift

PHPの__getメソッドではまったところ

PHPでハマったことがあったので書きます。常識的なことだったらすみません。。

__getメソッドとは

__getメソッドは存在しないプロパティへのアクセスがあったときに呼ばれます。
__getメソッドはPHPのオーバーロード機能の1つです。PHPのオーバーロード機能はプロパティやメソッドを動的に生成する機能で、Javaとかのメソッドのオーバーロードとは全然違いますのでご注意ください。

__getメソッドを使ったサンプルクラス

以下のようなクラスを作ります。

<?php 

class Sample
{
    private $_array;

    public function __construct()
    {
        $this->_array = array();
        $this->_array['test'] = 'hogehoge';
    }

    public function __get($name)
    {
        if (isset($this->_array[$name]) === false) {

            throw new Exception("Sample::${name} is undefined.");
        }

        return $this->_array[$name];
    }
}

上記サンプルクラスでは存在しないプロパティへのアクセスがあった場合、__getメソッドが呼ばれ、プライベートプロパティの$_arrayの要素から取得するようになっています。

<?
require_once 'sample.php';

$obj = new Sample();
echo $obj->test;
// 出力> hogehoge

今回はまったところ

上記サンプルクラスをそのまま使います。下記のコードの実行結果はどうなるでしょうか?

<?php
require_once 'sample.php';

$obj = new Sample();
if (empty($obj->test) === true) {
    echo 'empty!!';
} else {
    echo 'not empty';
}

上記コードを実行すると「empty!!」が出力されます。$obj->testは__getメソッドで動的に生成されているはずなのになんででしょうか。

原因:isset関数とempty関数のときは__issetメソッドが呼ばれているから

__isset() は、 isset() あるいは empty() をアクセス不能プロパティに対して実行したときに起動します。

PHP: オーバーロード - Manual

つまり存在しないプロパティをisset関数、empty関数の引数として渡すと__getメソッドではなく__issetメソッドが呼び出されます。上記サンプルクラスでは__issetメソッドが定義されていなかったのでisset関数、empty関数の引数として使われた場合$obj->testは常にfalseを返していたということです。

上記サンプルクラスを修正

__issetメソッドを定義します。これでisset関数、empty関数の引数の場合も$_arrayの要素から探すようになります。

<?php 

class Sample
{
    private $_array;

    public function __construct()
    {   
        $this->_array = array();
        $this->_array['test'] = 'hogehoge';
    }   

    public function __get($name)
    {   
        if (isset($this->_array[$name]) === false) {

            throw new Exception("Sample::${name} is undefined.");
        }   

        return $this->_array[$name];
    }   

    public function __isset($name)
    {   
        if (isset($this->_array[$name]) === false) {

            return false;
        }   

        return $this->_array[$name];
    }   
}

まとめ

__getメソッドを利用する場合は同時に__issetメソッドも定義しましょうー。

プログラミングPHP 第2版

プログラミングPHP 第2版