views:

103

answers:

3

According to the Law of Demeter, can you call methods on returned objects?

E.g.

<?php
class O
{
    public function m($http)
    {
        $response = $http->get('http://www.google.com');
        return $response->getBody(); // violation?
    }
}
?>

$http->get() returns an object. Does this count as an object created/instantiated within M? If you can not call methods on it (according to LoD), how would you handle this situation?

+4  A: 

This is not a violation of the Law of Demeter, given:

More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:

  • O itself
  • M's parameters
  • any objects created/instantiated within M
  • O's direct component objects
  • a global variable, accessible by O, in the scope of M

Since $response is an object that is created within M, you can invoke a method upon that object without violation. However, it would be a violation to access properties beyond getBody():

$length = $response->getBody().length;

Sometimes you can say that the law can be simplified by saying it's the "one dot" rule, meaning that you can access one property or method deep.

Jeff Schumacher
Except that the dot operator in PHP is for concatenating strings. :-) Slight brainfart in that last `.length` bit, I think.
janmoesen
+2  A: 

On the one hand, $response appears to have been created within method m, so the answer would appear to be yes.

On the other hand, since $http has been passed in to m, the object returned by $http->get() that is now represented by $response might be a member of $http that might have been created prior to entry to m.

Considering the "only one dot" (or, in this case arrow) interpretation of the Law, rewriting the body of your function as return $http->get('http://www.google.com')-&gt;getBody(); suggests that it might be a violation. Saving the intermediate members as local variables seems like a dodgy way to avoid the one-dot principle.

I can't give a definitive answer. To some extent, I think it depends on how much you trust the $http->get() to give you a newly created object rather than a pre-existing member.

Paul Butcher
A: 

One possibility to solve this is to create the object within m(), and let http->get() fill it with information.

class O
{
    public function m($http)
    {
        $response = new HttpResponse();
        $http->get('http://www.google.com', & $response);
        return $response->getBody(); // no violation, since we made $response ourselves.
    }
}
Sjoerd