6

I know that private visibility in most of the OOP languages (if not all) define privacy in a class basis, i.e. different instances of the same class, can access private properties/methods of each other.

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. 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); 
4
  • If that is the case then why do you need multiple instances? Commented Jun 22, 2015 at 13:31
  • I don't totally understand your question, but it seems like the singleton pattern would help. Commented Jun 22, 2015 at 13:32
  • I thought about a singleton too but that would mean he would use only 1 object, that's why I am asking why he needs multiple instances Commented Jun 22, 2015 at 13:33
  • Because product A has a prize, but if sold with product B, a discount is done. I believe that a Cart object holding both products would be the best design but I wanted to know how to avoid this kind of things though Commented Jun 22, 2015 at 13:35

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a good answer. However it does not address my question at all. What happens if I have to avoid such behavior (as I mentioned in my question) because the class is a legacy class and cannot be fully refactored? I know that the design is bad, but still I'm curious on how to prevent/fix/amend the behavior i've described above (if it's possible).
1

You can also achieve this with the 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); 

6 Comments

Why do you need to pass the ReflectionClass instance into the method from outside?! What a terrific method signature that is... O_o
Still not quite sure what this does though. Why do you need to test whether the property is private? You already know that, because you declared it to be so...
Because objects of the same type will have access to each others private and protected members. Instead of making $productB->_prize 0. This tells you, that you can't.
Sure, I understand that. Still, the property is private, it says so right there at the top of the class. You know that already. The check will always be false. Why write it? You may as well write if (false), it makes as much sense.
Agreed, it will always return "Is private property". I'm just showing possibilities for the OP. Because his question is: What is the best way to avoid instances of the same class to access eachother private methods/properties?
|
0

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

Comments

0

Don't access any properties at all without getters and setters. 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.

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.