简体   繁体   English

Php/OOP 如何避免同一个类的实例访问其他对象的私有属性/方法

[英]Php/OOP How to avoid instances of the same class to access private properties/methods from other objects

I know that private visibility in most of the OOP languages (if not all) define privacy in a class basis, ie different instances of the same class, can access private properties/methods of each other.我知道大多数 OOP 语言(如果不是全部)中的私有可见性以类为基础定义隐私,即同一类的不同实例可以访问彼此的私有属性/方法。

I want to prevent this and I want to know what is the best design/implementation in order to do this without a negative performance impact .我想防止这种情况发生,我想知道什么是最好的设计/实现,以便在不产生负面性能影响的情况下做到这一点。

For example, I know that I could implement an AOP and use notations, but this would lead to a performance decrease since the languange engine would have to create the reflection of the class and check the annotation.例如,我知道我可以实现 AOP 并使用符号,但这会导致性能下降,因为语言引擎必须创建类的反射并检查注释。 So, basically, my question is, what is the best way to avoid instances of the same class to access each other's private methods/properties?所以,基本上,我的问题是,避免同一类的实例访问彼此的私有方法/属性的最佳方法是什么?

Example:例子:

class Product
{
    private $_prize;
    public function __construct($prize)
    {
        $this->_prize = $prize;
    }

    public function calculateDiscount(Product $extraProduct)
    {
        $extraProduct->_prize = 0; //How to avoid this?
    }
}

$productA = new Product(10);
$productB = new Product(25);
$productA->calculateDiscount($productB);

Simply don't write code which accesses other entities' privates, period.只是不要编写访问其他实体私有的代码,句号。 The visibility modifiers are there to help you not shoot yourself in the foot too easily.能见度调节器可帮助您不至于轻易射中自己的脚。 They're not a lock and key.它们不是锁和钥匙。 There are any number of ways in which you can still "circumvent" "access protection".您仍然可以通过多种方式“规避”“访问保护”。 Just be a responsible adult and not modify properties except when you write a $this-> before it.做一个负责任的成年人,不要修改属性,除非你在它之前写了一个$this->

You can also achieve this with the ReflectionClass您也可以使用ReflectionClass实现此目的

class Product
{
    private $_prize;
    public function __construct($prize)
    {
        $this->_prize = $prize;
    }

    public function calculateDiscount(Product $extraProduct)
    {
        if(!(new ReflectionClass($extraProduct))->getProperty('_prize')->isPrivate()){
            $extraProduct->_prize = 0; //How to avoid this?
        } else {
            echo "Is private property"; 
        }
    }
}

$productA = new Product(10);
$productB = new Product(25);
$productA->calculateDiscount($productB);

Im not sure but :我不确定但是:

class Product
{
    private $_prize;
    public function __construct($prize)
    {
        $this->_prize = $prize;
    }

    public function calculateDiscount(Product $extraProduct)
    {
        $extraProduct->setPrize(0); 
    }

    public function setPrize( $v ) {
       $this->_prize = $v;
    }
}
$productA = new Product(10);
$productB = new Product(25);
$productA->calculateDiscount($productB);

Don't access any properties at all without getters and setters.在没有 getter 和 setter 的情况下,根本不要访问任何属性。 Then in your getters and setters, check if the calling context is the same class through (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT)[0]["object"] ?? null) === $this .然后在你的 getter 和 setter 中,通过(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT)[0]["object"] ?? null) === $this检查调用上下文是否是同一个类。

For example:例如:

class Foo{
    private $bar;
    public function getBar(){
        return $this->bar;
    }
    private function setBar($bar){
        self::assertCalledByThis();
        $this->bar = $bar;
    }

    private static function assertCalledByThis(){
        $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);
        $fromObject = $trace[1]["object"] ?? null; // context calling setBar()
        $toObject = $trace[0]["object"] ?? null; // context calling assertCalledByThis()

        assert($fromObject === $toObject);
    }
}

Of course, your getBar and setBar can be replaced by __get() and __set(), but then you must not declare the field, or the magic methods will not be called.当然,你的getBarsetBar可以用 __get() 和 __set() 代替,但是你一定不能声明字段,否则魔法方法不会被调用。

This is a given oop behavior not only in PHP.这是一个给定的 oop 行为,不仅在 PHP 中。 PHP manual describes this here . PHP 手册在这里对此进行描述。 So this is your code which offers this feature.所以这是您提供此功能的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM