views:

479

answers:

4

Stemming from this question on using __get() and __set() to access private variables, I'd like to get the input on how they are used in general. I am wondering when or where would be the best time to use a overloading function, and where you have used one (if you have).

Just to be clear, we are talking about these functions: http://us2.php.net/manual/en/language.oop5.magic.php

A: 

Some sample:

class formatedContainer {
    private $holder;
    protected $mode = "formated";

    public function __set($var, $value) {
        $formated = chunk_split($value, 4, "-");
        if(substr($formated, -1) == "-") 
            $formated = substr($formated, 0, strlen($formated) - 1);
        $this->holder[$var] = array('formated' => $formated, 'plain' => $value);
    }

    public function __get($var) {
        return $this->holder[$var][$this->mode];
    }

    public function getPlain() {
        $this->mode = "plain";
    }

    public function getFormated() {
        $this->mode = "formated";
    }
}

$texts = new formatedContainer();
$texts->myText = md5(uniqid());
$texts->anotherText = md5("I don't change!");

//Prints something like: 440e-6816-b2f5-7aa5-9627-9cc8-26ef-ef3b
echo $texts->myText;

$texts->getPlain();

//Prints something like: 8559d37c5a02714dca8bd1ec50a4603a
echo "<br/>" . $texts->anotherText;

Kinda useless, but I think you can get an idea. :}

Nathan
+1  A: 

I use __get() and __set() to access elements of a private array, i.e.:

class Something {
    private $data;

    public function __set($key, $value) {
        //put validation here
        $this->data[$key] = $value;
    }

    public function __get($key) {
        if (!array_key_exists($this->data, $key)) {
             throw new Exception("Invalid member $key.");
        } else {
             return $this->data[$key];
        }
    }
}

So with some validation, something like $person->age = "asdf" would throw an exception immediately (whereas it would be fine if age were a public member.)

Also in the __set() you can limit what keys are valid if you don't want arbitrary 'members' in your class.

Jake
But what higher value does this have than $person['age'], the common usage?
Flavius Stef
In __set(), not only can you limit which properties are allowed, like Jake said, but you can validate the value being set.
grantwparks
+2  A: 

Lazy Models Getters (using __get())

I don't remember using PHP's magic methods too often in my apps, but I remember one situation where __get() was very useful.

Back in the days I was developing an application in CakePHP framework that had a lot of models and all models that are used in specific controller were initialized even if method make use only of one or two of them (that's how Cake was working). So I decided to change that to lazy models to lazy (loading models when they are used for the first time).

All I did is I added a very simple __get() function that looked for a model with specific name and loaded it. It was like 3-4 lines of code. I defined that in AppController (all CakePHP classes derives from that controller) and suddenly my app gained speed and used lower memory.

I took it further later on and also made lazy components loading in the same way.

Dynamic Model Methods (using __call())

Another good example, also from CakePHP, is how Cake searches on models. Basically you have two methods for that: find() and findAll() in every model, but you can also search using methods findBy<FieldName>() and findAllBy<FieldName>().

In example if you have db table

notes(id, date, title, body)

And create Cake model for that. You can use methods such as findById(), findByTitle() and so on. You need only CamelCase db field and you can do a search on any field much quicker.

Cake does it by using __call() magic method. This method is called if you are trying to execute a method that doesn't exists and then it just runs find() or findAll() with conditions dynamically created from method name and parameters. This is very simple to implement and can give you really a lot of benefits.

RaYell
A: 

There's a lot of examples on the Web, using __get() and __set() in conjunction with a private "property array". The interesting twist I wanted in my class definitions, is to be able to actually declare public properties and still use these magic interceptors -- for more self documenting code and giving my IDE the ability to do code completion, etc. Normally, if those properties are declared, __get() and __set() will not get called. I found that if I unset() those same properties in my class constructor, I could get the best of both worlds.

grantwparks