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

时间:2015-06-22 13:26:40

标签: php oop

我知道大多数OOP语言(如果不是全部)的私有可见性在类的基础上定义隐私,即同一类的不同实例可以访问彼此的私有属性/方法。

我想阻止这一点,我想知道什么是最好的设计/实施,以便没有负面的性能影响

例如,我知道我可以实现AOP并使用符号,但这会导致性能下降,因为languange引擎必须创建类的反射并检查注释。所以,基本上,我的问题是,避免同一个类的实例访问彼此的私有方法/属性的最佳方法是什么?

示例:

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);

5 个答案:

答案 0 :(得分:4)

只是不要写代码来访问其他实体'私人,期间。可见性修饰符可以帮助你不会轻易拍摄自己的脚。他们不是锁和钥匙。你可以通过多种方式避免"规避" "访问保护"。只是一个负责任的成年人而不是修改属性,除非你在它之前写了$this->

答案 1 :(得分:1)

您也可以使用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);

答案 2 :(得分:0)

我不确定但是:

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);

答案 3 :(得分:0)

如果没有getter和setter,请不要访问任何属性。然后在getter和setter中,通过(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT)[0]["object"] ?? null) === $this检查调用上下文是否是同一个类。

例如:

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);
    }
}

当然,您的getBarsetBar可以替换为__get()和__set(),但是您不能声明该字段,否则不会调用魔术方法。

答案 4 :(得分:0)

这是给定的oop行为,不仅在PHP中。 PHP手册介绍了此here。这就是您的代码,提供了此功能。