3

源于这个关于使用__get()__set()访问私有变量的问题,我想了解它们的一般使用方式。我想知道何时何地是使用重载函数的最佳时间,以及你在哪里使用过重载函数(如果你有的话)。

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

4

4 回答 4

3

惰性模型吸气剂(使用 __get())

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

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

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

后来我更进一步,并以同样的方式加载了惰性组件。

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

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

例如,如果您有 db 表

notes(id, date, title, body)

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

蛋糕通过使用__call()魔术方法来做到这一点。如果您尝试执行不存在的方法,然后它只是运行find()findAll()使用从方法名称和参数动态创建的条件,则会调用此方法。这实现起来非常简单,并且可以给您带来很多好处。

于 2009-07-25T07:02:24.457 回答
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->age = "asdf" 这样的东西会立即抛出异常(而如果 age 是公共成员就可以了。)

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

于 2009-07-25T06:45:40.513 回答
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;

有点没用,但我想你可以得到一个想法。:}

于 2009-07-25T02:59:52.867 回答
0

网上有很多例子,使用__get()__set()结合私有“属性数组”。我希望在我的类定义中实现有趣的转折,即能够实际声明公共属性并仍然使用这些神奇的拦截器——用于更多的自我记录代码并让我的 IDE 能够完成代码完成等。通常,如果这些属性已声明,__get()不会__set()被调用。我发现如果我unset()在类构造函数中使用相同的属性,我可以两全其美。

于 2009-07-27T04:43:42.843 回答