【问题标题】:Best Practices for __get() and __set() [closed]__get() 和 __set() 的最佳实践 [关闭]
【发布时间】:2012-12-25 15:57:00
【问题描述】:

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

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

【问题讨论】:

  • 您引用的页面标题中的“魔术方法”一词让我立即感到怀疑。 ;)

标签: php oop magic-methods


【解决方案1】:

惰性模型 Getter(使用 __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 数据库字段,您可以更快地搜索任何字段。

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

【讨论】:

    【解决方案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() 中限制哪些键是有效的。

    【讨论】:

    • 但这比常用的$person['age']有什么更高的价值呢?
    • 在 __set() 中,您不仅可以像 Jake 所说的那样限制允许的属性,还可以验证设置的值。
    【解决方案3】:

    一些示例:

    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;
    

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-02
        • 2010-10-06
        • 2011-10-28
        • 2010-09-10
        • 2011-10-11
        • 1970-01-01
        • 2014-04-26
        相关资源
        最近更新 更多