Page 1 of 1

Can't figure it out how it works...

Posted: Mon Nov 12, 2007 5:03 am
by dwnthk
Hi there,

I am reading a book on PHP. There is the example codes in the book:

Code: Select all

<?php

abstract class PropertyObject implements Validator {
   protected $propertyTable = array();
   protected $data;
   ....
   function __construct($arData) { 
      $this->data = $arData;
   } 
   function __get($propertyName) {
      ...
   }

   function __set($propertyName, $value) { 
      ...
      if (method_exists($this, 'set'. $propertyName)) {
           return call_user_func(array($this, 'set' . $propertyName), $value);
      } else ...
      ...
   }
}

?>
In the other script:

Code: Select all

<?php
...
class Address extends PropertyObject {
   
    function __construct($arData) {
       parent::__construct($arData);
       $this->propertyTable['address']='addressid';
       $this->propertyTable['state']='cstate';
       ...
    }
 
    function validate() {
       if(strlen($this->state) !=2 ) { ... }     // Where does $this->state come from?
       ...
       if (!$this->address) { ... }    // Again, where does $this->address come from?
       ...
    }

}
?>
In the above codes, the class Address has no properties declared. I am not sure where the $this->state and $this->address come from?

And the double underscore (__set and __get) does have some real functionalities in the programming or it is just a way the PHP programmers will do? If I use "_set" or "set" instead of "__set" will change the program?

Thanks.

Dave

Posted: Mon Nov 12, 2007 12:10 pm
by feyd
__get and __set, like __construct (and several other methods) are called magic methods. They are not invoked directly by you (normally) but rather automatically by PHP. In this particular case, the properties "state" and "address" are requested by the second snippet. Since they are requested, the __get method will be called. I will assume that the removed code from the first snippet would access the "propertyTable" property of PropertyObject to find those values.

Posted: Tue Nov 13, 2007 5:41 am
by dwnthk

Code: Select all

<?php
require_once('Validator.php');
abstract class PropertyObject implements Validator {
   
   protected $propertyTable = array();
   protected $changedProperties = array();
   protected $data;
   protected $errors = array();

   public function __construct($arData) {
      $this->data = $arData;
   }   // function __construct()

   function __get($propertyName) {
      if (!array_key_exists($propertyName, $this->propertyTable))
          throw new Exception ("Invalid property \"$propertyName\"!"); 
      if (method_exists($this, 'get' . $propertyName))  {
         return call_user_func(array($this, 'get'.$propertyName));       // never run this code?
      } else {
         return $this->data[$this->propertyTable[$propertyName]];
      }   // if method_exists      
   }   // function __get()

    function __set($propertyName, $value) {
      if (!array_key_exists($propertyName, $this->propertyTable))
          throw new Exception ("Invalid property \"$propertyName\"!");
      if (method_exists($this, 'set' . $propertyName)) {
          return call_user_func( array($this, 'set' . $propertyName), $value);      // never run this code?
       } else {
          ....
       }
    }   // function __set()

}  // class PropertyObject
It is more or less the complete code of the PropertyTable class (hope I am not against the copyright right here now :lol: ).

The code "call_user_func(...)" would never be run in this PropertyTable class right? There isn't any 'set'.$propertyName in this class. Is it for the subclasses?

In the subclass Address class which extends from PropertyTable:

Code: Select all

<?php
require_once('PropertyTable.php');
class Address extends PropertyObject {

   function __construct($addressid) {
      $arData = DataManager::getAddressData($addressid);   // static function to get data from database
      parent::__construct($arData);
      $this->propertyTable['addressid'] = 'addressid';
      $this->propertyTable['address1'] = 'address1';
      $this->propertyTable['address2'] = 'address2';
      $this->propertyTable['state'] = 'state';
   }  // function __construct()

   function validate() {
      if (strlen($this->state) !=2 ) {                             // where is $this->state come from?
         $this->errors['state'] = 'Please choose a valid state.';
      }
      ....
    }    // function validate()
}   // class Address
I can't figure out where is the $this->state coming from?
And the __construct() would be called when we 'new' a object. When the __get and __set would be called automatically?

Sorry... it is a bit long for read :?

Dave

Posted: Tue Nov 13, 2007 10:34 am
by feyd
dwnthk wrote:The code "call_user_func(...)" would never be run in this PropertyTable class right? There isn't any 'set'.$propertyName in this class. Is it for the subclasses?
They are intended for subclasses. Since PropertyObject is an abstract class you can't actually have an instance of it (directly.)
dwnthk wrote:I can't figure out where is the $this->state coming from?
What do you mean? It's used to call the __get method.
dwnthk wrote:And the __construct() would be called when we 'new' a object. When the __get and __set would be called automatically?
All three are called automatically for you based on your actions; __construct for new foo, __get for $foo->bar, __set for $foo->bar = 2.