Using the __CALL Magic Method to Simplify Work

My primary reason for using call is to avoid creating, deleting, modifying a myriad a of get/set methods whose only purpose in life is to return, or set a primitive property. I want to avoid using __set, __get for reasons I give in the link to my webpage.

If you take a peek at the Jon Levensold videos (the end of video # 5, and beginning of video # 6) this precisely what he does.

After watching the two videos above I found this:

This shows the code on my webpage:

This is a comment from the code in the previous link, which summarizes the problem.

* __call as I have set it up below, can set variable primitive types, as well
* as arrays, but can only return primitives (no arrays) as I currently have it 
* setup. I did not want to use __set and __get, I wanted to use __call only.
* looking at the colors property which contains a multi-dimensional array
* Using __call overloading as defined here:
* you can set a primitive using : $storage->setBr("<br>");
* you can get a primitive using : echo $storage->getBr();
* you can set an array such as $colors as shown on the next line:
* $storage->setColors
* (
* array
*   (
*       'foreground' => array
*       (
*           "header"    => "black",
*           "block"     => "orange",
*           "body"      => "black",
*           <snip> ... </snip>
*       )
*   )
* );  // End of : $storage->setColors
* you can get any of the elements in the multi-dimensional array as follows:
* echo "$storage->getColors('foreground')->getBody();   // returns "black"
* I cannot retrieve an entire array using __call, by calling:
* $aObj = $storage->getUsers(5)->getBooks(1);           // fails to return the array
* $aArray = (array) $aObj;                              // casting to array does not help
* I had to create a specific method: public function getBookArray($user_no, $book_no)
* in order to retrieve the entire array, something I did not want to do. I was hoping 
* to be able to do both set/get using __call and only create specific methods whenever 
* internal calculations, or changing other affected variables, or other actions need 
* to be taken.
* The $message_no's are temporary until I come up with a finished version.

I can with the code I have so far at:

( 1 ) set/retrieve primitives,
( 2 ) set arrays,
( 3 ) set and retrieve elements of an array,
( 4 ) but cannot figure out using __call how to retrieve entire arrays.

I would be grateful for any help.

Bill Hernandez
Plano, Texas

Can you elaborate more on why you want to avoid __set and __get? Your code comments only point to the video and there I didn’t hear any reasons why not __set and __get. I’ve just implemented __get and __set for my active record classes and am happy with the result so I’d like to hear what advantages __call has. When using __get I don’t find any problems returning arrays.

* I cannot retrieve an entire array using __call, by calling:
* $aObj = $storage->getUsers(5)->getBooks(1);           // fails to return the array

As I see it the problem you have is that you want the above statement to return


Now the problem is that


returns an array so you can’t call the method getBooks(1) on an array. You can’t do anything about it if you return an array and want to use the chained method syntax above. The solution might be to return an object instead of array, so this:


would have to return an object and then set up the object to support ArrayAccess, Iterator, Countable, etc. so that you can use it as an array. Of course, these will not be true arrays and many array functions will not work with them but if you don’t mind this limitation that’s the way to go. If really in need you can convert the object to a real array and then use array functions on that.

See this:

Maybe I’m not fully grasping the problem, but it looks like you could do what you want to do pretty simply (of course, that’s a relative measure) by extending ArrayObject (see the links in the previous post). With that you could write a quick __call to implement your get/set, and if you wanted to get at the array-values as arrays (rather than the object) then it’s just a matter of (array) casting it, or calling getArrayCopy().

I updated the demo, and attached a download zip file.

interesting that __call returns the array as a protected object on line 145

return new self($this->data[$methodProperty][$arguments[0]]);

but if the request is for a primitive (not an array) that is an element of a protected array, then line 150

returns a public primitive ?

return $this->data[$methodProperty];

Line 372 shows that \$data which is an array

IF \$data is a protected var nothing prints here, and an error is generated

IF \$data is a public var, it prints OK, but setting it to public defeats purpose of all this…

I have no idea why the difference ?

why an element of a protected array is returned as a public primitive and yet the array returned as an object is returned as protected. I am sure it all makes a lot of sense, but I thought __call was acting as a proxy for getSomething(), when there is NO real getSomething().

$v1 = \\$storage->getUsers(5);   // returns a protected user object

$v2 = $storage->getUsers(5)->getBooks(1);  // returns a protected book object

$v3 = \\$storage->getUsers(5)->getBooks(1)->getTitle();
                  // returns a protected book title string as public

I’ve played around with this for about three days now, and am thinking I might have to go back to __set, __get…

Thanks for the help.

Bill Hernandez
Plano, Texas

Bill, forgive me if this seems dumb on my part but, could you explain again what the problem is since there is a lot of code, and a lot of commenting on behaviour, but what is your ultimate goal here and why is the current behaviour not sufficient?

Salathe and Lemon Juice,

First of all thank you both for trying to help me…

I just got home, and will try to put my thoughts together in a clearer way than I did with all the code. As soon as I get something together I will respond…

I didn’t want you to think I was ignoring your replies attempting to help me.

Best Regards

Bill Hernandez
Plano, Texas

You might get more replies if you posted your specific problematic code here in a short form instead of posting links to your site where you have code several pages long. Most people don’t have time to read and understand all of this. Please narrow down the problematic portion, post it here and ask a specific question.

good point…

I will try to come up with something brief over the weekend.

Thank You !