Search code examples
phpmagic-methods

PHP Magic methods to use property as array or string


I have some property $abc (type array) in object:

$this->abc = array(
    'id' => 123,
    'status' => 'close'
);

There is some solution to using this property as array or string? Like that:

echo $this->abc; // return first element of array: 123
echo $this->abc['status']; // return element by key: close

Maybe getter and setter or Reflection?

EDIT:
I prepare some like this, but all returns id value:

class Test {

    private $abc;

    public function __construct() {
        $this->abc = array(
            'id' => '123',
            'status' => 'close'
        );
    }

    public function __get($key) {
        if ($key === 'abc') {
            echo $this->abc['id'];
        }
    }
}

$t = new Test();

echo $t->abc['id']; // return 123 - correct!
echo $t->abc['status']; // return 123 - incorrect, should be return 'close' string
echo $t->abc; // return 123 - correct

Any suggestion?


Solution

  • Actually you can't do exactly what your example shows.

    Magic methods (what a silly name, btw) simply allow you to get and set properties, so that some_object->a can be handled with custom code, but you cannot tell PHP to handle
    some_object->a and some_object->a[0] differently.

    You are free to have your custom getter return an int, an array or an elephant, but that's it.

    EDIT: Your code does nothing but print abc['id'] each time the property is referenced.

    abc is still handled as any plain old property.

    Let's replace echo with return

    public function __get($key) {
        if ($key === 'abc') {
            return$this->abc['id'];
        }
    }
    

    Now whenever you reference abc, the getter gives you "123".
    Demonstration:

    echo $t->abc['id'];     // 'id' evaluates to 0, so result is "1" ("123"[0])
    echo $t->abc['status']; // same thing
    echo $t->abc;           // "123" - correct (of sorts)
    echo $t->abc[1];        // "2" (2nd character of "123")
    

    You are also free do do stupid things like that:

    class fairytale {
        private static $handsome =
            array ("Prince Valliant", "Superman", "Flash Gordon");
        private static $ugly     = 
            array ("Michael Moore", "Condoleezza Rice", "Ronald McDonald");
    
        function __get ($prop)
        {
            if ($prop=='frog')
                return self::$handsome;
            if (preg_match ('/^frog\\[([0-9]*)\\]$/', $prop, $res))
                return self::$ugly[$res[1]];
        }
    }
    
    function kiss ($prince)
    {
        echo "$prince appears in a puff of smoke...\n";
    }
    
    $pond = new fairytale();
    $frog1 = $pond->frog[0]; // <-- array subscript parsed before getter is called
    $frog2 = 'frog[0]';
    $frog2 = $pond->$frog2;  // <-- array subscript parsed inside getter
    
    kiss ($frog1);
    kiss ($frog2); // <--- surprise!
    

    As a side note, abusing custom getters/setters to turn frogs into princes might be a lot of fun and a fine display of PHP expertise, but it's unlikely to produce readable and maintainable code.
    Just my opinion, of course.