When I first started coding in Magento, it was also my first time coding using PHP. Double Whammy! I had been used to coding in the land of Java/JSP where everything was "typed" and everything was defined. Imagine my surprise when I started reading through the code and I started seeing things like "getCustomerName()" or "setCustomerEmail($email)" that were NOWHERE to be found! Let me take a minute to explain what is going on in the mysterious Varien_Object.
A LARGE majority of classes in the Magento code base eventually extend from the Varien_Object. This little beauty can be found here: magento_base/lib/Varien/Object.php.
One of the cool/dangerous/useful things in PHP is the __call() function. This guy is the function that is called if the function being called doesn't exist. Another piece of the puzzle is the $_data variable which is an array that is stored in the Varien_Object. For reference, I will include the snipped of code that can be found in the __call() function in the Varien_Object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
publicfunction__call($method,$args)
{
switch(substr($method, 0, 3)) {
case'get':
//Varien_Profiler::start('GETTER: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
$data=$this->getData($key, isset($args[0]) ?$args[0] : null);
//Varien_Profiler::stop('GETTER: '.get_class($this).'::'.$method);
return$data;
case'set':
//Varien_Profiler::start('SETTER: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
$result=$this->setData($key, isset($args[0]) ?$args[0] : null);
//Varien_Profiler::stop('SETTER: '.get_class($this).'::'.$method);
return$result;
case'uns':
//Varien_Profiler::start('UNS: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
$result=$this->unsetData($key);
//Varien_Profiler::stop('UNS: '.get_class($this).'::'.$method);
return$result;
case'has':
//Varien_Profiler::start('HAS: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
//Varien_Profiler::stop('HAS: '.get_class($this).'::'.$method);
returnisset($this->_data[$key]);
}
thrownewVarien_Exception("Invalid method ".get_class($this)."::".$method."(".print_r($args,1).")");
}
|
Let's pretend that we are working with a variable called $customer which is a Mage_Customer_Model_Customer object which extends Mage_Core_Model_Abstract, which extends Varien_Object. If you where to:
1
|
$customer->setDogsName('Rover');
|
You would naturally look for the function "setDogsName()" in the Mage_Customer_Model_Customer class...and not find it.
Then you would look for "setDogsName()" in the Mage_Core_Model_Abstract class...and not find it.
Lastly, you would look for "setDogsName()" in the Varien_Object class...and still not find it.
What's happening??? Well, because the function does not exist, the call ends up in the __call() function that parses the function call apart and ends up setting the value 'Rover" into the $_data array with the key of 'dogs_name'. Here is the code that does it:
1
2
3
4
5
6
|
case'set':
//Varien_Profiler::start('SETTER: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
$result=$this->setData($key, isset($args[0]) ?$args[0] : null);
//Varien_Profiler::stop('SETTER: '.get_class($this).'::'.$method);
return$result;
|
Now, reverse the situation. I can just as easily call:
1
|
$customer->getDogsName();
|
...and not find that function anywhere.
Just as before, you will end up in the __call() function where you will end up looking into the $_data array for the key "dogs_name" and returning the result. Here is the code:
1
2
3
4
5
6
|
case'get':
//Varien_Profiler::start('GETTER: '.get_class($this).'::'.$method);
$key=$this->_underscore(substr($method,3));
$data=$this->getData($key, isset($args[0]) ?$args[0] : null);
//Varien_Profiler::stop('GETTER: '.get_class($this).'::'.$method);
return$data;
|
Although this method of dynamically handling getters and setters might be confusing, just think of all the code you don't have to write anymore! It becomes even more magically awesome when you realize that all of the database tables map to models and all of the column names become getters and setters. Boom! My mind just exploded.