# __get() "feature"

- Thread: https://externals.io/message/13823
- Original archive: https://news-web.php.net/php.internals/13823
- Started by Jason Perkins on 2004-11-11T15:21:23+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #13823 — Jason Perkins — 2004-11-11T15:21:23+00:00

URL: https://externals.io/message/13823#13823

I've ran into an issue using __get() and want to ascertain if this is 
how it was intended to work or if it's a bug. The general notion of 
what I'm attempting to accomplish using __get() is that a given object 
will potentially contain other objects, but these contained objects 
aren't known (or generated) until runtime.

For example, we'll instantiate a sales_order object and then, using its 
has_a() method, add a customer object to it. To prevent cascades of 
objects being instantiated, I'd plan to use lazy initialization - the 
customer object won't be instantiated until the first time that it's 
accessed through the customer class. The problem that I'm having is 
that lazy initialization in PHP 5 is accomplished via the __get() 
method which is called when an attribute (or contained class in this) 
isn't available - it's passed the name of the property that wasn't 
found and that's not enough information for me to return the attribute 
of the contained object that was being accessed. Here's some quickly 
written code with extra code stripped that'll demonstrate what I mean:

<?

class sales_order {
     ...

   public function has_a( $class ) {
     $this->relationships[ $class ] = 'has_a';
   }

   public function __get( $class ) {
     if(array_key_exists( $class, $this->relationships )) {
       if( $this->relationships[ $class ] == 'has_a') {
         $this->$class  = new $class( $this->id );
         return;
       }
     }
   }
}

So if $attribute exists in the relationships array, it's instantiated 
(and, yeah, I plan to move the contained objects into a declared array. 
one thing at a time :) )

$sales_order = new sales_order;
$sales_order->has_a( customer );
print $sales_order->customer->name;

The last line fails, because __get is passed only 'customer' and not 
'customer->name' - I have no way of knowing what attribute of customer 
was being accessed, so I can't return the requested data. Running this 
code:

$sales_order = new sales_order;
$sales_order->has_a( customer );
print $sales_order->customer->name;
print $sales_order->customer->name;

the fourth line works, because the customer object was instantiated 
during line three (line three still fails to return a value). Is this 
an issue with __get() or is this how it was intended to work?


--
Jason N Perkins

---

## #13824 — Marcus Boerger — 2004-11-11T19:17:33+00:00

URL: https://externals.io/message/13823#13824 · In reply to: #13823

Hello Jason,

Thursday, November 11, 2004, 4:21:23 PM, you wrote:

> I've ran into an issue using __get() and want to ascertain if this is 
> how it was intended to work or if it's a bug. The general notion of 
> what I'm attempting to accomplish using __get() is that a given object 
> will potentially contain other objects, but these contained objects 
> aren't known (or generated) until runtime.

> For example, we'll instantiate a sales_order object and then, using its 
> has_a() method, add a customer object to it. To prevent cascades of 
> objects being instantiated, I'd plan to use lazy initialization - the 
> customer object won't be instantiated until the first time that it's 
> accessed through the customer class. The problem that I'm having is 
> that lazy initialization in PHP 5 is accomplished via the __get() 
> method which is called when an attribute (or contained class in this) 
> isn't available - it's passed the name of the property that wasn't 
> found and that's not enough information for me to return the attribute 
> of the contained object that was being accessed. Here's some quickly 
> written code with extra code stripped that'll demonstrate what I mean:

> <?

> class sales_order {
>      ...

>    public function has_a( $class ) {
>      $this->relationships[ $class ] = 'has_a';
>    }

>    public function __get( $class ) {
>      if(array_key_exists( $class, $this->relationships )) {
>        if( $this->relationships[ $class ] == 'has_a') {
>          $this->$class  = new $class( $this->id );
>          return;
Change the above line to:
          return $this->$class;

>        }
>      }
>    }
> }

> So if $attribute exists in the relationships array, it's instantiated 
> (and, yeah, I plan to move the contained objects into a declared array. 
> one thing at a time :) )

> $sales_order = new sales_order;
> $sales_order->has_a( customer );
> print $sales_order->customer->name;

> The last line fails, because __get is passed only 'customer' and not 
> 'customer->name' - I have no way of knowing what attribute of customer 
> was being accessed, so I can't return the requested data. Running this 
> code:

> $sales_order = new sales_order;
> $sales_order->has_a( customer );
> print $sales_order->customer->name;
> print $sales_order->customer->name;

> the fourth line works, because the customer object was instantiated 
> during line three (line three still fails to return a value). Is this 
> an issue with __get() or is this how it was intended to work?


> --
> Jason N Perkins




-- 
Best regards,
 Marcus                            mailto:helly@php.net

---

## #13825 — Jason Perkins — 2004-11-11T19:33:02+00:00

URL: https://externals.io/message/13823#13825 · In reply to: #13824

> > […]
>
> > […]
>
> > […]
>
> > […]
> Change the above line to:
>           return $this->$class;

I'd tried that initially as:

public function __get( $class ) {
   if(array_key_exists( $class, $this->relationships )) {
     if( $this->relationships[ $class ] == 'has_a') {
       $this->$class  = new $class( $this->id );
       return $this->$class;
     }
   }
}

called from:

$sales_order = new sales_order( 1 );
$sales_order->has_a( 'customer' );
print $sales_order->customer->address1;

results in no output being generated. Using a suggestion of Todd Ruth's:

public function __get( $class ) {
   if(array_key_exists( $class, $this->relationships )) {
     if( $this->relationships[ $class ] == 'has_a') {
       $value = $this->$class  = new $class( $this->id );
       return $value;
     }
   }
}

and then running that same print code from above results in:

  123 maple street

being generated. Which is the test data that I have for the customer 
table associated with the sales_order with primary id of 1. Weird, huh?

--
Jason N Perkins
