簡體   English   中英

Php/OOP 如何避免同一個類的實例訪問其他對象的私有屬性/方法

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

我知道大多數 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);

只是不要編寫訪問其他實體私有的代碼,句號。 能見度調節器可幫助您不至於輕易射中自己的腳。 它們不是鎖和鑰匙。 您仍然可以通過多種方式“規避”“訪問保護”。 做一個負責任的成年人,不要修改屬性,除非你在它之前寫了一個$this->

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

我不確定但是:

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

在沒有 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() 代替,但是你一定不能聲明字段,否則魔法方法不會被調用。

這是一個給定的 oop 行為,不僅在 PHP 中。 PHP 手冊在這里對此進行描述。 所以這是您提供此功能的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM