php 5 中使用get成员方法返回对象可能存在的问题。

"错误的类设计可能会改变本不应该改变的成员属性。"这个问题是在看 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 的反射应该也是非常有用的。嗯,继续研究,继续研究……

路漫漫……其修远……

Join the Conversation

1 Comment

Leave a comment

Your email address will not be published. Required fields are marked *