基于PHP静态类的原罪详解


Posted in PHP onMay 06, 2013

黑格尔有句名言:存在即合理。以此为论据的话,静态类的使用必然有其合理性。不过物极必反,一旦代码过于依赖静态类,其劣化的结局则不可避免。这就好比罂粟作为一种草本植物,有其在药理上的价值,但如果肆无忌惮的大量使用,它就变成了毒品。

什么是静态类

所谓静态类指的是无需实例化成对象,直接通过静态方式调用的类。代码如下:

<?php
class Math
{
    public static function ceil($value)
    {
        return ceil($value);
    }
    public static function floor($value)
    {
        return floor($value);
    }
}
?>

此时类所扮演的角色更像是命名空间,这或许是很多人喜欢使用静态类最直接的原因。

静态类的问题

本质上讲,静态类是面向过程的,因为通常它只是机械的把原本面向过程的代码集合到一起,虽然结果是以类的方式存在,但此时的类更像是一件皇帝的新衣,所以可以说静态类实际上是披着面向对象的壳儿,干着面向过程的事儿。

面向对象的设计原则之一:针对接口编程,而不是针对实现编程。这有什么不同?打个比方来说:抛开价格因素,你喜欢独立显卡的电脑还是集成显卡的电脑?我想绝大多数人会选择独立显卡。独立显卡可以看做是针对接口编程,而集成显卡就就可以看做是针对实现编程。如此说来针对实现编程的弊端就跃然纸上了:它丧失了变化的可能性。

下面杜撰一个文章管理系统的例子来具体说明一下:

<?php
class Article
{
    public function save()
    {
        ArticleDAO::save();
    }
}
?>

Article实现必要的领域逻辑,然后把数据持久化交给ArticleDAO去做,而ArticleDAO是一个静态类,就好像焊在主板上的集成显卡一样难以改变,假设我们为了测试代码可能需要Mock掉ArticleDAO的实现,但因为调用时使用的是静态类的名字,等同于已经绑定了具体的实现方式,Mock几乎不可能,当然,实际上有一些方法可以实现:
<?php
class Article
{
    private static $dao = 'ArticleDAO';
    public static funciton setDao($dao)
    {
        self::$dao = $dao;
    }
    public static function save()
    {
        $dao = self::$dao;
        $dao::save();
    }
}
?>

有了变量的介入,可以在运行时设定具体使用哪个静态类:
<?php
Article::setDao('MockArticleDAO');
Article::save();
?>

虽然这样的实现方式看似解决了Mock的问题,但是首先它修改的原有的代码,违反了开闭原则,其次它引入了静态变量,而静态变量是共享的状态,有可能会干扰其它代码的执行,所以并不是一个完美的解决方案。

补充说明,利用动态语言的特性,其实可以简单的通过require一个不同的类定义文件来实现Mock,但这样做同样有弊端,设想我们在脚本里需要多次变换实现方式,但实际上我们只有一次require的机会,否则就会出现重复定义的错误。

对象的价值

如果放弃静态类,转而使用对象,应该如何实现文章管理系统的例子?代码如下:

<?php
class Article
{
    private $dao;
    public function __construct($dao = null)
    {
        if ($dao === null) {
            $dao = new ArticleDAO();
        }
        $this->setDao($dao);
    }
    public function setDao($dao)
    {
        $this->dao = $dao;
    }
    public function save()
    {
        $this->dao->save();
    }
}
?>

实际上,这里用到了人们常说的依赖注入技术,通过构造器或者Setter注入依赖的对象:
<?php
$article = new Article(new MockArticleDAO());
$article->save();
?>

对象有自己的状态,不会发生共享状态干扰其它代码的执行的情况。

当然,静态类有好的一面,比如说很适合实现一些无状态的工具类,但多数时候,我的主观倾向很明确,多用对象,少用静态类,避免系统过早的固化。顺便说一句,希望别有人告诉我静态类比对象快之类的说教,谢谢。

PHP 相关文章推荐
PHP_NETWORK_GETADDRESSES: GETADDRINFO FAILED问题解决办法
May 04 PHP
PHP解密Unicode及Escape加密字符串
May 17 PHP
WampServer搭建php环境时遇到的问题汇总
Jul 23 PHP
PHP模拟asp中response类实现方法
Aug 08 PHP
PHP加密3DES报错 Call to undefined function: mcrypt_module_open() 如何解决
Apr 17 PHP
非常经典的PHP文件上传类分享
May 15 PHP
PHP下的浮点运算不准的解决方法
Oct 27 PHP
php获取excel文件数据
Apr 21 PHP
php中的异常和错误浅析
May 03 PHP
PHPMailer使用QQ邮箱实现邮件发送功能
Aug 18 PHP
ThinkPHP5.0 图片上传生成缩略图实例代码说明
Jun 20 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
Apr 02 PHP
用php制作简单分页(从数据库读取记录)的方法详解
May 04 #PHP
PHPMailer邮件发送的实现代码
May 04 #PHP
用php实现选择排序的解决方法
May 04 #PHP
基于PHP 面向对象之成员方法详解
May 04 #PHP
php中判断数组是一维,二维,还是多维的解决方法
May 04 #PHP
PHP命名空间(Namespace)的使用详解
May 04 #PHP
PHP更新购物车数量(表单部分/PHP处理部分)
May 03 #PHP
You might like
Laravel 4 初级教程之安装及入门
2014/10/30 PHP
laravel获取不到session的三种解决办法【推荐】
2018/09/16 PHP
javascript让setInteval里的函数参数中的this指向特定的对象
2010/01/31 Javascript
JavaScript中的Array对象使用说明
2011/01/17 Javascript
在vs2010中调试javascript代码方法
2011/02/11 Javascript
写了10年的Javascript也未必全了解的连续赋值运算
2011/03/25 Javascript
jquery中通过父级查找进行定位示例
2013/06/28 Javascript
js获取php变量的实现代码
2013/08/10 Javascript
EasyUI实现第二层弹出框的方法
2015/03/01 Javascript
js实现宇宙星空背景效果的方法
2015/03/03 Javascript
Javascript aop(面向切面编程)之around(环绕)分析
2015/05/01 Javascript
详解JavaScript对W3C DOM模版的支持情况
2015/06/16 Javascript
js实现的全国省市二级联动下拉选择菜单完整实例
2015/08/17 Javascript
js带前后翻页的图片切换效果代码分享
2015/09/08 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
2015/10/16 Javascript
javascript回到顶部特效
2016/07/30 Javascript
javascript表单正则应用
2017/02/04 Javascript
使用vue开发移动端管理后台的注意事项
2019/03/07 Javascript
微信小程序实现的一键拨号功能示例
2019/04/24 Javascript
微信小程序如何播放腾讯视频的实现
2019/09/20 Javascript
[46:27]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第一局
2016/03/02 DOTA
[02:53]2018年度DOTA2最佳战队-完美盛典
2018/12/17 DOTA
剖析Python的Tornado框架中session支持的实现代码
2015/08/21 Python
Python 快速实现CLI 应用程序的脚手架
2017/12/05 Python
django 发送邮件和缓存的实现代码
2018/07/18 Python
Python Sphinx使用实例及问题解决
2020/01/17 Python
探讨HTML5移动开发的几大特性(必看)
2015/12/30 HTML / CSS
美国办公用品购物网站:Quill.com
2016/09/01 全球购物
Kangol帽子官网:坎戈尔袋鼠
2018/09/26 全球购物
屈臣氏泰国官网:Watsons TH
2021/02/23 全球购物
早餐连锁店计划书
2014/01/08 职场文书
文案策划求职信
2014/04/14 职场文书
2015毕业实习推荐信
2015/03/23 职场文书
2015年信访维稳工作总结
2015/04/07 职场文书
2015年成本会计工作总结
2015/10/14 职场文书
logback如何自定义日志存储
2021/08/30 Java/Android