When do/should I use __construct(), __get(), __set(), and __call() in PHP?

后端 未结 10 701
再見小時候
再見小時候 2020-12-05 08:16

A similar question discusses __construct, but I left it in my title for people searching who find this one.

Apparently, __get and __set take a parameter that is the

相关标签:
10条回答
  • 2020-12-05 08:59

    Overloading methods is especially useful when working with PHP objects that contain data that should be easily accessable. __get() is called when accessing a non-existent propery, __set() is called when trying to write a non-existent property and __call() is called when a non-existent method is invoked.

    For example, imagine having a class managing your config:

    class Config
    {
        protected $_data = array();
    
        public function __set($key, $val)
        {
            $this->_data[$key] = $val;
        }
    
        public function __get($key)
        {
            return $this->_data[$key];
        }
    
        ...etc
    
    }
    

    This makes it a lot easier to read and write to the object, and gives you the change to use custom functionality when reading or writing to object. Example:

    $config = new Config();
    $config->foo = 'bar';
    
    echo $config->foo; // returns 'bar'
    
    0 讨论(0)
  • 2020-12-05 08:59

    One good reason to use them would be in terms of a registry system (I think Zend Framework implements this as a Registry or Config class iirc), so you can do things like

    $conf = new Config();
    $conf->parent->child->grandchild = 'foo';
    

    Each of those properties is an automatically generated Config object, something akin to:

    function __get($key) {
        return new Config($key);
    }
    

    Obviously if $conf->parent already existed, the __get() method wouldn't be called, so to use this to generate new variables is a nice trick.

    Bear in mind this code I've just quoted isn't functionality, I just wrote it quickly for the sake of example.

    0 讨论(0)
  • 2020-12-05 09:07

    They're for doing "clever" things.

    For example you could use __set() and __get() to talk to a database. Your code would then be: $myObject->foo = "bar"; and this could update a database record behind the scenes. Of course you'd have to be pretty careful with this or your performance could suffer, hence the quotes around "clever" :)

    0 讨论(0)
  • 2020-12-05 09:08

    PHP allows us to create class variables dynamically which can cause problems. You can use __set and __get methods to restrict this behavior..see the example below...

    class Person { 
          public $name;
          public function printProperties(){
           print_r(get_object_vars($this));
          }
    }
    
    $person = new Person();
    $person->name = 'Jay'; //This is valid
    $person->printProperties();
    $person->age = '26';  //This shouldn't work...but it does 
    $person->printProperties();
    

    to prevent above you can do this..

    public function __set($name, $value){
        $classVar = get_object_vars($this);
        if(in_array($name, $classVar)){
        $this->$name = $value;
        }
    }
    

    Hope this helps...

    0 讨论(0)
  • 2020-12-05 09:09

    This page will probably be useful. (Note that what you say is incorrect - __set() takes as a parameter both the name of the variable and the value. __get() just takes the name of the variable).

    __get() and __set() are useful in library functions where you want to provide generic access to variables. For example in an ActiveRecord class, you might want people to be able to access database fields as object properties. For example, in Kohana PHP framework you might use:

    $user = ORM::factory('user', 1);
    $email = $user->email_address;
    

    This is accomplished by using __get() and __set().

    Something similar can be accomplished when using __call(), i.e. you can detect when someone is calling getProperty() and setProperty() and handle accordingly.

    0 讨论(0)
  • 2020-12-05 09:10

    Another useful application of magic methods, especially __get and __set and __toString is templates. You can make your code independent from template engine just by writing simple adapter that uses magic methods. In case you want to move to another template engine, just change these methods only.

    class View {
    
        public $templateFile;
        protected $properties = array();
    
        public function __set($property, $value) {
            $this->properties[$property] = $value;
        }
    
        public function __get($property) {
            return @$this->properties[$property];
        }
    
        public function __toString() {
            require_once 'smarty/libs/Smarty.class.php';
            $smarty = new Smarty();
            $smarty->template_dir = 'view';
            $smarty->compile_dir = 'smarty/compile';
            $smarty->config_dir = 'smarty/config';
            $smarty->cache_dir = 'smarty/cache';
            foreach ($this->properties as $property => $value) {
                $smarty->assign($property, $value);
            }
            return $smarty->fetch($this->templateFile);
        }
    
    }
    

    Hidden benefit of this approach is that you can nest View objects one inside another:

    $index = new View();
    $index->templateFile = 'index.tpl';
    
    $topNav = new View();
    $topNav->templateFile = 'topNav.tpl';
    
    $index->topNav = $topNav;
    

    And in index.tpl, the nesting looks like that:

    <html>
    <head></head>
    <body>
        {$topNav}
        Welcome to Foobar Corporation.
    </body>
    </html>
    

    All nested View objects gets converted to string (HTML to be exact) on the fly, as soon as you echo $index;

    0 讨论(0)
提交回复
热议问题