Search code examples
phpmagic-methodslazy-loading

Call __get() on protected properties with -> operator?


My team is using lazyloading techniques to load sub-objects from our database. To do this we're using the magic __get() method and making a database call. All of our properties are protected so the __get method gets called from outside of the object but our issue is that it doesn't get called from within the object without using $this->__get($name);

So my question is: Is it possible to force __get() to be called with the normal chaining operator even from within the object?

If I want to chain object access I currently have to do:

$this->__get('subObject')->__get('subObject')->__get('subObject') 

Is it possible to write the following, but have it still call __get()?

$this->subObject->subObject->subObject

Thanks, Jordan


Solution

  • Jordan,

    PHP won't call the __get() method unless the property is inaccessible—either because it doesn't exist, or because of visibility. When the property is hidden from the calling scope the __get() method is called because the property is inaccessible. When the property is referenced and is available to the calling scope, __get() will never fire. (It's not meant to fire for an existing/accessible property.)

    To work around this you have to rename your internal properties. Either prefix them with a name, underscore, or store them in a common array parameter with a special name. The following is somewhat contrived, but it ought to demonstrate how you can deal with this situation.

    class MyObject {
       protected $lazyloads = array();
    
       protected function lazyload($relation) {
         // ...
       }
    
       public function __get($key) {
         if (isset($this->lazyloads[$key]) {
           return $this->lazyloads[$key];
         } else {
           return $this->lazyload($key);
         }
       }
    }
    

    See: http://www.php.net/manual/language.oop5.overloading.php#object.get