Your second example makes the problem clearer but I get a weird feeling it is somewhat theoretical, in other words I’ve never encountered it in my coding. The reason for this, I think, is that I believe using objects like this is bad practice - sometimes this would be justifiable but most of the time the problem should be solved differently.
I think one object should not change properties of other objects nor should it be allowed to. A slight improvement would be to make foo private and create a getter and setter for it but then we are only masking the problem. A better way would be not to construct objects as data collections to be manipulated by outside code but rather make them do specific tasks. Therefore, your don’t expose public properties and methods are not setThis()
, getThis()
, etc. but rather specific verbs like doThis()
, fetchThat()
, transformDataLikeThis()
, saveData()
, etc. An exception to this rule would be value objects, which are simply enclosures for data and don’t contain any programming logic. But from your theoretical example I can’t tell whether you are talking about value objects or service objects. See point 9 “Mixing Service Objects with Value Objects” at http://misko.hevery.com/2008/07/30/top-10-things-which-make-your-code-hard-to-test/
Your problem is also mutable vs immutable objects. You should decide whether you keep your objects mutable or immutable. In your example the $a
object is clearly mutable and I think if a method changes an object’s value then it should not return it since this would be duplicated logic. But you should make the method name clear to represent this action like this:
$b->setObjectsFooToBar2($a);
You can find a similar situation in native DateTime object:
$dt = new DateTime;
$dt->modify('+1 day'); // this changes $dt object value
The difference is that you are changing another object’s value. Personally, I would avoid this and class A should not allow this. An example of a better solution would be to make class A expose a method for adding data, let’s say A is a collection of list items (but it could be anything else):
class A {
private $listItems;
public function __construct() {
$this->listItems = ['Always present first item.'];
}
public function addItem($item) {
$this->listItems[] = $item;
}
public function getItems() {
return $this->listItems;
}
}
class B {
public function addBar2ItemToListObject(A $a) {
$a->addItem('bar2');
}
}
$a = new A;
$b = new B;
$b->addBar2ItemToListObject($a);
echo $a->getItems();
To make it even nicer you can use an interface to specify what kind of objects can be manipulated by addBar2ItemToListObject()
so that it doesn’t have to be only A
but also other objects with the method addItem()
:
interface itemCollection {
public function addItem($item);
}
class A implements itemCollection {
private $listItems;
public function __construct() {
$this->listItems = ['Always present item.'];
}
public function addItem($item) {
$this->listItems[] = $item;
}
public function getItems() {
return $this->listItems;
}
}
class B {
public function addBar2ItemToListObject(itemCollection $collection) {
$collection->addItem('bar2');
}
}
$a = new A;
$b = new B;
$b->addBar2ItemToListObject($a);
echo $a->getItems();