Please let me correct my last post, and sorry for the double posting :)

Justin Hannus wrote:
The way ActionScript 2.0 solves this is....

<?php

class Foo
{
    private $_fooProp;


     function __get fooProp()
     {
         return $this->_fooProp; // $_fooProp is read only
     }

    function __set barProp($val)
    {
        // logic to set barProp...
    }

     function __get barProp()
     {
         // logic to get barProp...
     }
}
?>

To allow for BC, if there is no identifier after the __set/__get then the existing rules apply.

-Justin

Derick Rethans wrote:

Hello!

we're finding some problems with property overloading (__get() and __set()). Here is an RFC describing what we'd like to see changed. Please comment on this.


Introduction:
PHP currently supports property overloading with the magic functions __get()
and __set(). Those methods are called when the code "echo $object->a" or
"$object->a = 42" are executed and the property "a" is not declared in the
class. The magic methods are responsibly for:
- checking if the property actually "exists"
- setting the value or returning the value depending on the action

Problems:
1. There is no way to document the 'virtual' properties with any of the existing
   documentation tools (such as phpdoc and doxygen)
2. There is no way how the magic methods know if a specific 'virtual' property exists or not as those properties are not declared usually - unless you
   define an array with property names as a class constant (which is not
   allowed either).
3. There is no way for the magic methods to return a meaningfull error when a property doesn't "exist". Of course it is possible to throw an error with "trigger_error" or "throw" in case a property doesn't "exist" in a specific class, but the file and line numbers would not match the actually get/set action. debug_backtrace() can be used to retrieve the correct file and line, but as you have to do this for every class where you want to use setters and
   getters *and* you have to implement your own error message rendering
   function this is not really a suitable option either.


Solutions:
- For problem 1. we can introduce a keyword (or use an existing one) to define that it is a virtual property ('abstract' or 'virtual' come to mind). When
  declaring it like this it's easy to document, and we can also implement
visibility for those virtual properties. Marcus already has a patch for
  this somewhere, which uses the "abstract" keyword for this purpose:

<?php
class Base
{
    /**
     * @var int   Contains all X
     */
    abstract public $x = 1;
/**
     * @var int   Contains all Y
     */
    abstract protected $y = 2;

    //  abstract private $z = 3; abstract properties cannot be private
}
?>

- In combination to the introduced keyword we need an easy way to check if a passed property name is declared in the class as 'virtual'. Currently (with
  the 'abstract' keyword properly implemented) you'd have to do:

<?php
class Base
{
    abstract public $x = 1;
function __get($name)
    {
        try {
            $prop = new ReflectionProperty('Base', $name);
            if ( !$prop->isAbstract() ) {
                /* throw error */
            }
        } catch ($e) {
            /* throw error */
        }
    }
}

$b = new Base();
echo $b->foo;
?>

This is ofcourse overly complicated. A better workable solution would be -
  without breaking BC (suggestions for syntax here are very welcome):

<?php
class Base
{
    abstract public $x = 1;
function __get($name)
    {
        if (!self::isVirtual($name))) {
            /* throw error */
        }
    }
}

$b = new Base();
echo $b->foo;
?>

- Problem 3 can be solved by:
  * allowing optional by-ref parameters to the __set
    and __get function, so that their signatures become:

    function __set($name, $value [, &$error] )
    function __get($name [, &$error] )

If the parameter is not given things behave just like they do now -> __set and __get can not throw meaningful errors with the correct file/line of the
    conflicting statement

    If the parameter is used in the function's declaration and is set to
"false" when the __set or __get function returns, the engine can throw an error on the assignment line with the correct file/line combination. If it's set to "true" (or "null") then the engine should not throw any error.

* Use a different __set and __get function for 'abstract' properties, then the engine can already determine if you're doing something wrong before
    executing the __set and __get methods.


regards,
Derick


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to