1

Generally I have 3 classes, a container that holds an array of items and a special object that is another property of the container class. What I need to do is access the special object from an item object within the container. I see 2 ways of achieving this.

class Container {

    protected $object;
    protected $items = [];

    public function __construct() {
        $this->object = new SpecialObject;
    }

    public function setItem($index, Item $item) {
        $this->items[$index] = $item;
    }

    public function getItem($index) {
        return $this->items[$index];
    }

}

class Item {

    protected $container;

    public function __construct(Container $container) {
        $this->container = $container;
    }

    public function action() {
        $this->container->object;
    }
}

Or

class Container {

    protected $object;
    protected $items = [];

    public function __construct() {
        $this->object = new SpecialObject;

        Registry::set('SpecialObject', $this->object);
    }

    public function setItem($index, Item $item) {
        $this->items[$index] = $item;
    }

    public function getItem($index) {
        return $this->items[$index];
    }

}

class Item {

    public function action() {
        Registry::get('SpecialObject');
    }
}

With the first example the problem I'm concerned about is that there will be a reference within each Item object pointing to the container, which is not only redundant but if an item switches containers (for some reason, not intended) it will have a wrong container reference and could lead to trouble. The second one however implies that there will only be one instance of Container, which may not and probably will not be the case. I think there is no fool-proof way to grab the container of an item but what would you suggest is the "best" way to achieve this in terms of performance and avoiding bugs?

2
  • Why would the Item need to know, in which Container is it stored? You are creating a circular dependency, which in some cases might be a good design, in your case it screams bad implementation. If you need the SpecialObject in your Item class, set it into the Item using a method and manipulate it that way.
    – Andy
    Commented Sep 23, 2015 at 14:10
  • @DavidPacker I used to have it set up that way, each Item had a SpecialObject reference, but it is just giving me the sensation of bad implementation. I think the items should not store references to anything they should just be able to get the object from the container they currently reside in.
    – php_nub_qq
    Commented Sep 23, 2015 at 14:14

1 Answer 1

2

A few solutions come to mind:

In stead of calling that action on the Item, call it on the Container. Something like this:

class Container {
    ...

    public function actionOnItem($index) {
        // do stuff with the item and the special object
        $this->object;
        $this->items[$index];
    }
}

In stead of hard coding that dependency into the Item, you could inject it when you Item needs it. Something Along these lines:

class Item {
    ...
    public function action(SpecialObject $object) {
        // do stuff with the item and the special object
        $object;
        $this;
    }
}

And you could use it like this:

$item->action($container->object);

Another option would be to make a dedicated object for that Action, and inject both the Item and SpecialObject when you want it to do it's thing. Something in this order.

class ItemAction {

    private $object;

    public function __construct(SpecialObject $object) {
        $this->object = $object;
    }

    public function action(Item $item) {
        // do stuff with the item and the special object
        $this->object;
        $item;
    }
}

Or perhaps something like this

class ItemAction {

    public static function action(Item $item, SpecialObject $object) {
        // do stuff with the item and the special object
        $object;
        $item;
    }
}

What would be the best option in your case is hard to tell and depends largely on the scope and size of your application, and even the framework you are (not) using. Perhaps you could try to give a real world example of what you are trying to achieve?...

Anyway, if it where up to me, Dependency Injection would be the way to go! And it has the added benefit of making your code easier to test. Even that SpecialObject would be injected into the Container if it where up to me, in stead of newing it up hardcoded inside your Container constructor.

1
  • Thank you for sharing your ideas, they are very good IMO. I ended up coding it like your first suggestion but I guess I didn't see dependency injection as an option because the action method from the example is actually a magic method __toString which doesn't accept parameters.
    – php_nub_qq
    Commented Sep 23, 2015 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.