3

我创建了一个实现 ArrayAccess 的类,并添加了一个函数来防止 WRITE 操作:

 $Obj->Add("key","something");
 $Obj->Add("key2","something2");
 $Obj->SetReadOnly(); // sets read only property
 unset($Obj["key2"]); // throws error, object is readonly

但是,我也想防止取消设置对象:

 unset($Obj);

我能做到吗?我听到建议。感谢帮助!。

4

4 回答 4

2

我无法想象你真的想这样做的任何情况。我也可以想象,当所有对象都被销毁时,这样做会导致脚本终止时出现严重问题。PHP 手册中关于在析构函数中抛出异常的内容如下:

笔记:

尝试从析构函数(在脚本终止时调用)抛出异常会导致致命错误。

上面的语句暗示如果您不在脚本终止阶段,您可以抛出异常,所以也许以下是可能的。

public function __destruct ()
{
    if ($this -> isReadOnly ())
    {
        throw new Exception ('Class is read-only');
    }
}

但是,正如手册指出的那样,这将在脚本关闭期间触发致命错误。

老实说,我看不出想要防止对象破坏的任何意义。应该由程序员来管理对象的生命周期。

于 2012-10-26T06:37:49.757 回答
2

unset()如果这是您要阻止的,则实际上并不会破坏对象。

仅当对象的所有引用都未设置或不再在范围内时,才会破坏对象。即便如此,在垃圾收集器运行之前它也不会发生。

因此,如果您担心某些代码会干扰您的对象,那么您已经做好了使用只读逻辑使其不可变的工作。

假设你有

$Obj = gotMyObjectSomehow();

并且您需要将其传递给您不想取消设置 $Obj 的其他代码。只要在函数内部调用该代码,就没有什么可担心的。如果你打电话

someFunction($Obj);

假设该函数取消了它传入的参数

function someFunction($anObj) {
    unset($anObj);
}

那么您的原始$Obj变量仍将被设置。

该函数创建引用原始对象的第二个变量,并在其自己的范围内使用它。

于 2012-10-26T06:58:03.223 回答
1

您无法控制未设置的变量名称,因为这些名称在技术上不是所引用对象的一部分。考虑以下:

$a = new MyObject();
$b = $a;

现在你有两个对同一个对象的引用。使用and之间没有区别,因为在 PHP 中对象总是通过引用使用(即你不必在第二行做)。所以两者和本质上是同一个对象;unsetting不会破坏对象, unsetting也不会破坏它;在对象被销毁之前,所有引用都需要取消设置。$a$b$b =& $a$a$b$a$b

于 2012-10-26T06:56:57.430 回答
0

我不认为你可以做你所要求的——不可能阻止一个变量像那样被取消设置。

然而,你上面的评论让我思考。你说:

....如果您想防止在第三方扩展中取消设置系统变量

因此,如果我理解正确,您的目标是确保在使用第三方代码(即您的软件)时,与之相关的所有变量都保持不变?

现在你还没有详细说明这个系统中有哪些变量。我们在问题中看到了一个对象,但想必还有更多?我猜你有很多东西可以联系在一起,对吧?在这类问题中提供更多背景信息会有所帮助;您所要求的实际事情是不可能的,但是对您想要实现的目标有所了解,我们可以提出替代方案。

好的。所以我的建议是:将您的对象创建为单例。纯粹主义者通常不赞成这种做法,但在这种情况下可能效果很好,具体取决于您正在做什么。这里的美妙之处在于您可以将对对象的所有访问封装在类方法中,这意味着使用您的代码的开发人员无权访问对象的主副本以取消设置它。

单例的工作方式如下:

<?php
class mySingletonClass {
    private static $masterObject=null;

    public static function getInstance() {
        if(!isset(self::$masterObject)) {
            self::$masterObject = new self;
        }
        return self::$masterObject;
    }

    private function __construct() {
        //your existing constructor, as it already exists, but marked as private.
    }

    //...and all the other methods as you already have them.
}

类构造方法是私有的,所以只能从类内的方法中访问。因此,你不能再这样做了new classname()。获取此类对象的唯一方法是从静态getInstance()方法中获取它。这里的关键是这个方法总是返回对象的相同副本。

$obj = mySingletonClass::getInstance();
unset($obj);
$obj = mySingletonClass::getInstance();  //will give the exact same object as the first time.

您可以根据需要取消设置,但原始对象仍然存在并且仍然可以访问。您的任何其他类都可以使用该getInstance()方法从程序中的任何位置获取同一对象的相同副本。这是一个坚不可摧的全局变量。

单例通常用于程序的主数据库连接对象,但在这里它可能对您有用。

我希望这会有所帮助。这是我能想到的接近你想要的东西的唯一方法。

于 2012-10-26T20:51:56.137 回答