"错误的类设计可能会改变本不应该改变的成员属性。"这个问题是在看 Java 的时候书中提到的。PHP5 默认传递的也是引用,那么可能也存在这个问题。于是跳下床来,做了个试验。果然……
先看一段代码:
<?php
/**
* privateClass
*
* 一个私有的类,在 publicClass 中使用
*/
class privateClass
{
/**
* name
*
* 保存一个名字
*
* @var string
* @access protected
*/
protected $name = '';
/**
* __construct
*
* 构造函数
*
* @param string $name
* @access public
* @return void
*/
public function __construct($name)
{
$this->setName($name);
}
/**
* getName
*
* 获得名字
*
* @access public
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* setName
*
* 设置名字
*
* @param string $name
* @access public
* @return void
*/
public function setName($name)
{
$this->name = $name;
}
}
/**
* publicClass
*
* 公共类
*/
class publicClass
{
/**
* priClass
*
* @var privateClass
* @access protected
*/
protected $priClass = null;
/**
* __construct
*
* 构造函数
*
* @param string $name
* @access public
* @return void
*/
public function __construct($name)
{
// 生成 privateClass 的对象
$this->priClass = new privateClass($name);
}
/**
* getName
*
* 返回名字
*
* @access public
* @return string
*/
public function getName()
{
// 返回名字
return $this->priClass->getName();
}
/**
* getPrivateClass
*
* 返回私有类
*
* @access public
* @return privateClass
*/
public function getPrivateClass()
{
// 获取私有类对象
// return clone $this->priClass;
return $this->priClass;
}
}
// 生成了名为 ‘Foo’的对象
$Foo = new publicClass('Foo');
// 取得了‘Foo’的私有对象
$priClass = $Foo->getPrivateClass();
// 开始一些操作
//
// 使用 $priClass 对象时进行了一些操作,比如临时改了名字
$priClass->setName('Bar');
//
// 结束一些操作
// 然后再次取得‘Foo’对象的名字,但是却发生了改变。
echo $Foo->getName();
?>
代码本身很好理解,看注释就应该能明白。正常来说 $Foo->getName() 得到的应该是 Foo。对引用比较熟悉的朋友会立刻指出,不对 $Foo->getName() 应该是 Bar。
没错是 Bar!但是这似乎不是在设计这两个类时希望得到的结果。publicClass 类并没有设置 setName 的成员方法,也隐含着 publicClass 不允许修改名字。但是由于某些原因,在编码时获得了 privateClass 的实例,可能由于逻辑需要临时改变了这个对象的一些属性。OK,作为一个临时变量,这没什么。但是作为引用,这就有问题了。
实际上绕过了类 publicClass 在名字这个属性上的约束,让不可变的属性发生了改变。很糟糕不是么?
不知道谁在自己的项目中使用过 clone 这个语法结构。我从来没有用过,之前总认为这个是没什么用的时髦玩意。但是PHP 语言本身也是相当精巧的。这个没用的玩意在这里居然有了用途:
public function getPrivateClass()
{
// 获取私有类对象
return clone $this->priClass;
}
将 publicClass::getPrivateClass() 方法改为上面的写法时,问题解决了……
这样看来 PHP 的反射应该也是非常有用的。嗯,继续研究,继续研究……
路漫漫……其修远……
Leave a Reply