【问题标题】:PHP - Zend say avoid Magic Methods?PHP - Zend 说避免魔术方法?
【发布时间】:2011-04-07 18:40:23
【问题描述】:

我正在阅读此页面 - http://deaduseful.com/blog/posts/50-php-optimisation-tips-revisited

其中一项建议是避免使用魔法方法,引用自 Zend Performance PDF,它没有给出建议避免使用它们的理由。

经过一些谷歌搜索(并在这里结束一个不相关的问题),我想知道是否有人在这方面有任何建议?

我在代码中经常使用 __get(),通常是为了保存我不经常使用的变量,例如

我可能有一个包含名称、描述、类别 ID、添加时间的表格

我的 get 看起来像这样:

公共函数 __get($name) { 开关($名称){ 案例“名称”: 案例“描述”: 案例“类别”: 案例“时间添加”: $result = do_mysql_query(); $this->name = $result['name']; $this->desc = $result['desc']; $this->category = $result['category']; $this->time_added = $result['time_added']; 返回 $this->{$name}; 休息; 默认: throw Exception("试图访问不存在的或私有的属性 - ".$name); } }

这似乎是一种很好的做事方式,因为我只会在需要时从数据库中获取一些东西,而且我可以引用 $article->time_added 之类的东西,而不是摆弄数组。

这是否会被认为是不好的做法和服务器上的额外负载?

如果子类与 get 中的某些内容不匹配,我通常会使用魔术方法扩展类并执行类似的操作。

公共函数 __get($name) { 开关($名称){ 案例“名称”: 案例“描述”: 案例“类别”: 案例“时间添加”: $result = do_mysql_query(); $this->name = $result['name']; $this->desc = $result['desc']; $this->category = $result['category']; $this->time_added = $result['time_added']; 返回 $this->{$name}; 休息; 默认: 返回父级::__get($name); } }

这会是不好的做法并且对性能不利吗?扩展魔术方法时,我的最大级别数是三个。

【问题讨论】:

标签: php performance magic-methods


【解决方案1】:

我用 PHP 魔术方法和本机 get/set 操作(在公共属性上)做了一些测试

结果:

魔术方法比本地访问慢得多。但是访问时间仍然很短,在 99.9% 的情况下都不会产生影响。

即使你在一个请求中进行 100 万次魔术方法访问,仍然只需要大约 0.1 秒...


“只读”是指通过魔术方法访问。 图片显示 PHP 5.5.9 和 PHP 7.0 结果。

这是基准脚本: https://github.com/stracker-phil/php-benchmark/blob/master/benchmark.php

【讨论】:

    【解决方案2】:

    是的,它们速度较慢...但差异是如此之小,以至于速度与代码是一个因素。为了更快的开发和维护,是否值得担心差异?

    查看magic benchmarks 了解统计信息

    【讨论】:

    • +1:你不能高估这种情绪。请记住,Premature Optimization Is The Root Of All Evil... 如果您将所有时间都花在担心微小的速度差异上,那么您将永远无法完成任何事情。以适合您的方式构建它,然后如果遇到问题,从那里重构。但是,您可以做出的最大性能改进是从非工作状态转换为工作状态。相比之下,其他一切都相形见绌......
    • 干杯这个链接真的很有帮助,你的观点非常正确,很难不陷入想要完美的代码而从未真正发布任何代码:D
    • 恕我直言,可维护代码比高性能代码更重要。想想看。投入更多硬件解决问题比投入更多开发人员解决问题要便宜。这就是 PHP 如此受欢迎的原因之一......现在,总是有一个权衡,所以我不建议忽略性能,但如果您不知道是否存在问题,请不要尝试微优化.. .
    • @ircmaxell,什么是非工作状态,什么是工作状态?
    • @kavoir.com “不工作”意味着软件不工作。工作意味着它有效。就这么简单。
    【解决方案3】:

    考虑使用array accessors

    class Record implements ArrayAccess {
    
        /**
         * @see ArrayAccess::offsetExists()
         *
         * @param offset $offset
         */
        public function offsetExists($offset) {
    
        }
    
        /**
         * @see ArrayAccess::offsetGet()
         *
         * @param offset $offset
         */
        public function offsetGet($offset) {
            //fetch and cache $result
    
            return $result[$offset];
        }
    
        /**
         * @see ArrayAccess::offsetSet()
         *
         * @param offset $offset
         * @param value $value
         */
        public function offsetSet($offset, $value) {
    
        }
    
        /**
         * @see ArrayAccess::offsetUnset()
         *
         * @param offset $offset
         */
        public function offsetUnset($offset) {
    
        }
    

    【讨论】:

    • 那有什么不同呢?你只是将四种魔法方法换成了其他四种魔法方法......
    • @ircmaxell 接口方法不是魔术方法。虽然我不能用数字备份,但我声称这些会比依赖拦截器运行得更快
    • @Gordon:速度较慢,请查看上述答案中的链接。是的,虽然它不是严格意义上的“魔法方法”,但它是一种魔法,因为接口能够实现类似魔法的功能(能够在对象上使用核心函数和语言结构)......
    • @ircmaxell 如果你这样说,那么是的,这是一个很好的观点。
    猜你喜欢
    • 1970-01-01
    • 2015-09-13
    • 1970-01-01
    • 2023-03-14
    • 2010-10-27
    • 1970-01-01
    • 2012-06-21
    • 2011-06-10
    • 2010-12-26
    相关资源
    最近更新 更多