【问题标题】:Php/OOP How to avoid instances of the same class to access private properties/methods from other objectsPhp/OOP 如何避免同一类的实例访问其他对象的私有属性/方法
【发布时间】:2015-06-22 13:26:40
【问题描述】:

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

我想防止这种情况发生,并且我想知道最好的设计/实现是什么,以便不会对性能产生负面影响

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

例子:

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

【问题讨论】:

  • 如果是这样,那你为什么需要多个实例?
  • 我不完全理解你的问题,但似乎singleton pattern 会有所帮助。
  • 我也想过单例,但这意味着他只会使用 1 个对象,这就是为什么我问他为什么需要多个实例
  • 因为产品A有奖品,但是如果和产品B一起卖,就打折了。我相信拥有两种产品的 Cart 对象将是最好的设计,但我想知道如何避免这种事情

标签: php oop


【解决方案1】:

不要编写访问其他实体的私人信息的代码,期间。可见性修改器是为了帮助你不会太轻易地在脚上开枪。它们不是锁和钥匙。您仍然可以通过多种方式“规避”“访问保护”。做一个负责任的成年人,不要修改属性,除非你在它前面写$this->

【讨论】:

  • 这是一个很好的答案。但是,它根本没有解决我的问题。如果我必须避免这种行为(正如我在问题中提到的那样)会发生什么,因为该类是遗留类并且不能完全重构?我知道设计很糟糕,但我仍然很好奇如何防止/修复/修改我上面描述的行为(如果可能的话)。
【解决方案2】:

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

【讨论】:

  • 为什么需要从外部将ReflectionClass 实例传递给方法?!多么棒的方法签名啊……O_o
  • 仍然不太清楚这是做什么的。为什么需要测试该属性是否为私有?你已经知道了,因为你宣称它是如此......
  • 因为相同类型的对象可以访问彼此的私有成员和受保护成员。而不是使$productB->_prize 0。这告诉你,你不能。
  • 当然,我明白那个。尽管如此,该属性仍然是private,它就在班级顶部这样说。你已经知道了。支票永远是假的。为什么要写?你也可以写if (false),这很有意义。
  • 同意,它将始终返回“是私有财产”。我只是在展示 OP 的可能性。因为他的问题是:避免同一类的实例访问彼此的私有方法/属性的最佳方法是什么?
【解决方案3】:

我不确定,但是:

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

【讨论】:

    【解决方案4】:

    不要在没有 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()代替,但是不能声明字段,否则魔法方法不会被调用。

    【讨论】:

      猜你喜欢
      • 2012-09-03
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      • 2017-12-20
      • 1970-01-01
      相关资源
      最近更新 更多