基于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批量生成随机用户名
Jul 10 PHP
PHP 数组基础知识小结
Aug 20 PHP
PHP安全性漫谈
Jun 28 PHP
php连接Access数据库错误及解决方法
Jun 20 PHP
PHP Class&amp;Object -- PHP 自排序二叉树的深入解析
Jun 25 PHP
PHP多个文件上传到服务器实例
Oct 29 PHP
php转换颜色为其反色的方法
Apr 27 PHP
php封装的图片(缩略图)处理类完整实例
Oct 19 PHP
yii2-GridView在开发中常用的功能及技巧总结
Jan 07 PHP
thinkphp实现把数据库中的列的值存到下拉框中的方法
Jan 20 PHP
PHP中检索字符串的方法分析【strstr与substr_count方法】
Feb 17 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
Mar 17 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
PHP sprintf() 函数的应用(定义和用法)
2012/06/29 PHP
CentOS安装php v8js教程
2015/02/26 PHP
如何用PHP做到页面注册审核
2017/03/02 PHP
PHP如何实现订单的延时处理详解
2017/12/30 PHP
javascript 终止函数执行操作
2014/02/14 Javascript
js简单的表格添加行和删除行操作示例
2014/03/31 Javascript
抛弃Nginx使用nodejs做反向代理服务器
2014/07/17 NodeJs
EasyUI,点击开启编辑框,并且编辑框获得焦点的方法
2015/03/01 Javascript
JS获取Table中td值的方法
2015/03/19 Javascript
jquery调整表格行tr上下顺序实例讲解
2016/01/09 Javascript
关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法
2016/06/30 Javascript
谈谈因Vue.js引发关于getter和setter的思考
2016/12/02 Javascript
Angular2使用jQuery的方法教程
2017/05/28 jQuery
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
vue组件 $children,$refs,$parent的使用详解
2017/07/31 Javascript
vue 解决循环引用组件报错的问题
2018/09/06 Javascript
前端Vue项目详解--初始化及导航栏
2019/06/24 Javascript
BootstrapValidator实现表单验证功能
2019/11/08 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
2020/06/11 Javascript
Python中用于返回绝对值的abs()方法
2015/05/14 Python
Python简单实现子网掩码转换的方法
2016/04/13 Python
Python找出最小的K个数实例代码
2018/01/04 Python
python验证码识别教程之利用滴水算法分割图片
2018/06/05 Python
pytorch使用Variable实现线性回归
2019/05/21 Python
python 实现生成均匀分布的点
2019/12/05 Python
python ubplot使用方法解析
2020/01/10 Python
CSS3系列之3D制作方法案例
2017/08/14 HTML / CSS
商务日语毕业生自荐信范文
2013/11/14 职场文书
十月份红领巾广播稿
2014/01/22 职场文书
县优秀教师事迹材料
2014/01/31 职场文书
学校四风对照检查材料
2014/08/28 职场文书
社区个人对照检查材料(群众路线)
2014/09/26 职场文书
热情服务标语
2014/10/07 职场文书
高中生个性发展自我评价
2015/03/09 职场文书
go web 预防跨站脚本的实现方式
2021/06/11 Golang
HTML5 语义化标签(移动端必备)
2021/08/23 HTML / CSS