是否可以真正限制此私有 属性 的访问?
Is it possible to truly limit access of this private property?
我在尝试中使用了三个技巧:
- 反射不能与动态 class 属性一起使用
访问动态 class 属性时必须调用 - __get() 或 __set()
- debug_backtrace() 可用于模拟类似于
private
的内容
对于具有私有非静态 属性 $bar
的 class Foo
,我想禁止 $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 之外的直接访问将被禁止。
- 反思属性
- PHP 致命错误:未捕获的 ReflectionException:属性 栏不存在
- 反射不适用于动态属性。它甚至没有通过
ReflectionClass::hasProperty()
检测到它的存在 :-)
Closure::bind
- 未测试,但我相信 debug_backtrace() 应该 return "file" 不同于 FILE 的文件定义了闭包。我只有
Foo
的正确用法,所以我不在乎,只要加载正确的代码即可。
假设没有写任何文件的权限,也没有扩展重定义class方法,但是可以加载任意PHP代码,有什么方法可以改变这个Foo->bar
属性?
经过一番修改,我得出结论,您要实现的目标是不可能的,而且毫无意义。
我会解释为什么。
A class 属性 有 3 种可能的可见性:public、protected 和私有。
如果是public,可以简单赋值修改值:
$foo->bar = "new value";
我们可以用 __set()
拦截这个吗?来自 PHP Manual:
__set() is run when writing data to inaccessible properties.
A public 属性 始终可用。
因此,根本没有机会拦截并进行检查,因为 __set()
不会被调用。
接下来,如果 属性 是 protected 或 private,则必须在 class 中声明它],
这意味着您可以使用 ReflectionProperty
或 Closure::bind
来修改它的值。
最后,您实际上可以通过将值存储在其他地方来确保调用 __set()
。
例如,在同一个对象中使用不同的名称,甚至在另一个对象中。
不幸的是,无论您将值存储在哪里,我上面的解释都适用,这就是为什么它毫无意义。
我在尝试中使用了三个技巧:
- 反射不能与动态 class 属性一起使用 访问动态 class 属性时必须调用
- __get() 或 __set()
- debug_backtrace() 可用于模拟类似于
private
的内容
对于具有私有非静态 属性 $bar
的 class Foo
,我想禁止 $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 之外的直接访问将被禁止。
- 反思属性
- PHP 致命错误:未捕获的 ReflectionException:属性 栏不存在
- 反射不适用于动态属性。它甚至没有通过
ReflectionClass::hasProperty()
检测到它的存在 :-)
Closure::bind
- 未测试,但我相信 debug_backtrace() 应该 return "file" 不同于 FILE 的文件定义了闭包。我只有
Foo
的正确用法,所以我不在乎,只要加载正确的代码即可。
- 未测试,但我相信 debug_backtrace() 应该 return "file" 不同于 FILE 的文件定义了闭包。我只有
假设没有写任何文件的权限,也没有扩展重定义class方法,但是可以加载任意PHP代码,有什么方法可以改变这个Foo->bar
属性?
经过一番修改,我得出结论,您要实现的目标是不可能的,而且毫无意义。 我会解释为什么。
A class 属性 有 3 种可能的可见性:public、protected 和私有。 如果是public,可以简单赋值修改值:
$foo->bar = "new value";
我们可以用 __set()
拦截这个吗?来自 PHP Manual:
__set() is run when writing data to inaccessible properties.
A public 属性 始终可用。
因此,根本没有机会拦截并进行检查,因为 __set()
不会被调用。
接下来,如果 属性 是 protected 或 private,则必须在 class 中声明它],
这意味着您可以使用 ReflectionProperty
或 Closure::bind
来修改它的值。
最后,您实际上可以通过将值存储在其他地方来确保调用 __set()
。
例如,在同一个对象中使用不同的名称,甚至在另一个对象中。
不幸的是,无论您将值存储在哪里,我上面的解释都适用,这就是为什么它毫无意义。