__get()和__set()的最佳实践

时间:2009-07-25 02:00:47

标签: php oop magic-methods

在使用__get()__set()访问私有变量时,我希望得到关于如何使用它们的输入question。我想知道什么时候或哪里是使用重载功能的最佳时间,以及你曾经使用过(如果有的话)的地方。

为了清楚起见,我们正在谈论这些功能:http://us2.php.net/manual/en/language.oop5.magic.php

4 个答案:

答案 0 :(得分:3)

懒惰模型获取者(使用__get())

我不记得在我的应用中经常使用PHP的魔术方法,但我记得__get()非常有用的一种情况。

回到过去,我在CakePHP框架中开发了一个应用程序,它有很多模型,并且在特定控制器中使用的所有模型都被初始化,即使方法仅使用其中的一个或两个(这就是Cake的工作方式) )。因此我决定将其更改为懒惰模型(在第一次使用时加载模型)。

我所做的就是添加了一个非常简单的__get()函数,该函数查找具有特定名称的模型并加载它。这就像3-4行代码。我在AppController中定义了(所有CakePHP类派生自该控制器),突然我的应用程序获得了速度并使用了较低的内存。

我后来进一步使用它,并以同样的方式加载了延迟组件。

动态模型方法(使用__call())

另一个很好的例子,也来自CakePHP,是Cake在模型上搜索的方式。基本上,您有两种方法:每个模型中都有find()findAll(),但您也可以使用方法findBy<FieldName>()findAllBy<FieldName>()进行搜索。

例如,如果你有db table

notes(id, date, title, body)

为此创建Cake模型。您可以使用findById()findByTitle()等方法。您只需要CamelCase数据库字段,您可以更快地搜索任何字段。

Cake使用__call()魔术方法完成它。如果您尝试执行不存在的方法,则会调用此方法,然后它只运行find()findAll(),并根据方法名称和参数动态创建条件。这很容易实现,可以给你带来很多好处。

答案 1 :(得分:2)

我使用__get()和__set()来访问私有数组的元素,即:

class Something {
    private $data;

    public function __set($key, $value) {
        //put validation here
        $this->data[$key] = $value;
    }

    public function __get($key) {
        if (!array_key_exists($this->data, $key)) {
             throw new Exception("Invalid member $key.");
        } else {
             return $this->data[$key];
        }
    }
}

所以通过一些验证,像$ person-&gt; age =“asdf”这样的东西会立即抛出异常(如果年龄是公共成员则会没事。)

同样在__set()中,如果您不想在班级中任意“成员”,您可以限制哪些键有效。

答案 2 :(得分:0)

一些样本:

class formatedContainer {
    private $holder;
    protected $mode = "formated";

    public function __set($var, $value) {
        $formated = chunk_split($value, 4, "-");
        if(substr($formated, -1) == "-") 
            $formated = substr($formated, 0, strlen($formated) - 1);
        $this->holder[$var] = array('formated' => $formated, 'plain' => $value);
    }

    public function __get($var) {
        return $this->holder[$var][$this->mode];
    }

    public function getPlain() {
        $this->mode = "plain";
    }

    public function getFormated() {
        $this->mode = "formated";
    }
}

$texts = new formatedContainer();
$texts->myText = md5(uniqid());
$texts->anotherText = md5("I don't change!");

//Prints something like: 440e-6816-b2f5-7aa5-9627-9cc8-26ef-ef3b
echo $texts->myText;

$texts->getPlain();

//Prints something like: 8559d37c5a02714dca8bd1ec50a4603a
echo "<br/>" . $texts->anotherText;

有点无用,但我想你可以得到一个主意。 :}

答案 3 :(得分:0)

网上有很多例子,将__get()__set()与私有“属性数组”结合使用。在我的类定义中我想要的有趣的转变是能够实际声明公共属性并仍然使用这些魔术拦截器 - 更多自我记录代码并使我的IDE能够完成代码完成等。通常,如果这些属性声明,__get()__set()将不会被调用。我发现,如果我unset()在我的类构造函数中使用相同的属性,我可以充分利用这两个世界。