是否有可能真正限制这个私人财产的访问?

时间:2017-01-08 08:17:43

标签: php oop reflection visibility pocketmine

我在尝试中使用了三个技巧:

  • 反射不能与动态类属性一起使用
  • 访问动态类属性时必须调用
  • __ get()或__set()
  • debug_backtrace()可用于模拟类似于private
  • 的内容

对于具有私有非静态属性Foo的类$bar,我想禁止$this之外的任何作用域修改其值。所以我这样做:

/** @property object $bar */
class Foo{
    public function __get($k){
        if($k === "bar") return $this->bar;
    }
    public function __set($k, $v){
        if($k === "bar"){
            $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);
            if($trace[0]["object"] !== $this or $trace[0]["file"] !== __FILE__) throw new RuntimeException("Illegal access");
            $this->bar = $v;
        }
    }
}

这应该(未经测试)不受三种访问的影响:

  • 直接访问
    • debug_backtrace()检查调用上下文是否来自$ this。在$ this以外直接访问将被禁止。
  • ReflectionProperty
    • PHP致命错误:未捕获ReflectionException:属性栏不存在
    • 反射不适用于动态属性。它甚至没有通过ReflectionClass::hasProperty()检测它的存在: - )
  • Closure::bind
    • 未经测试,但我认为debug_backtrace()应返回与 FILE 不同的“文件”,而是返回定义Closure的文件。我只能正确使用Foo,所以只要加载了正确的代码,我就不在乎了。

假设没有写入任何文件的权限而且没有扩展来重新定义类方法,但是可以加载任意PHP代码,是否有任何方法可以更改此Foo->bar属性?

1 个答案:

答案 0 :(得分:1)

经过一些修补,我得出结论,你想要实现的目标是不可能的,也是毫无意义的。 我将解释原因。

一个类属性有三种可能的可见性:公共受保护私有。 如果是公开,您可以使用简单的分配修改该值:

npm install -g grunt-cli

我们可以用$foo->bar = "new value"; 拦截这个吗?来自PHP Manual

  

__ set()在将数据写入不可访问的属性时运行。

始终可以访问公开属性。 因此,根本没有机会拦截并进行检查,因为__set()将不会被调用。

接下来,如果该属性是受保护私有,则必须在该类中声明它, 这意味着您可以使用__set()ReflectionProperty修改其值。

最后,您实际上可以通过将值存储在其他位置来确保调用Closure::bind。 例如,在同一对象中的不同名称下,或甚至在另一个对象中。 不幸的是,无论你在哪里存储价值,我上面的解释都会再次适用,这就是为什么它没有意义。