Only class Master could call registerMaster method. Is any way, pattern which will help me in this example?
There is no concept of Friend Classes in PHP, so there is no way to hide a public method from another class.
You could use inheritance and protected visibility
abstract class LinkedEntity {
protected $master;
protected $slave;
}
class Master extends LinkedEntity {
public function __construct(Slave $slave) {
$this->slave = $slave;
$this->slave->master = $this;
}
}
class Slave extends LinkedEntity {}
$slave = new Slave;
$master = new Master($slave);
Since Master and Slave now extend the same base class, the protected properties are accessible to them, but not to any other classes. The same would be true for protected methods defined in the LinkedEntity class. So you can put a protected registerMaster(Master $master) method and go through that instead of directly assigning the properties.
Personally, I find that not so pretty and I'd rather find out whether you really need the bidirectional association here or whether it's good enough to have a one way association, e.g. from Master to Slave only or vice versa.
Another, even worse option, would be to inspect the callstack:
class Slave {
private $master;
public function registerMaster(Master $master)
{
if (debug_backtrace(null, 2)[1]["class"] === Master::class) {
throw new RuntimeException("Only Masters may call Slaves");
}
$this->master = $master;
}
}
The method checks if the previous class in the call stack (the one that did the call to your registerMaster was actually a Master. However, when your methods depend on the information of who the callee was, it's usually a sign of bad design.
A third option would be to break through the visibility of the method in the Slave via Reflection, e.g.
class Master {
private $slave;
public function __construct(Slave $slave) {
$this->slave = $slave;
$fn = new ReflectionMethod($slave, 'registerMaster');
$fn->setAccessible(true);
$fn->invoke($slave, $this);
}
}
class Slave {
private $master;
private function registerMaster(Master $master)
{
$this->master = $master;
}
}
Again, this is not optimal, because a core principle of OOP is Information Hiding and we are breaking it here. We are breaking through the designated private visibility and force it to public for the Master. Also, this will not prevent any other objects from doing the same.
Masterthe ability to callregisterMaster()?