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:
- There is no way to document the 'virtual' properties with any of the existing
documentation tools (such as phpdoc and doxygen) - 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). - 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 statementIf 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
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
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:
- There is no way to document the 'virtual' properties with any of the existing
documentation tools (such as phpdoc and doxygen)- 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).- 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.
what about:
<?php
class GetSet0 {
function __get($name) {}
function __set($name, $value) {}
}
class GetSet1 {
property $x;
// or virtual $x, ...
}
class GetSet2 {
property $x { __get, __set }
function __get($name) {}
function __set($name, $value) {}
}
class GetSet3 {
property $x { getMethod, setMethod }
function getMethod() {}
function setMethod($value]) {}
}
?>
Features:
- Easy way to document properties
- No BC break with code relies on __get, __set
Clases GetSet0, GetSet1 and GetSet2 are equivalent and third class
GetSet3 use different methods to handle $x property;
There is a nice way to declare reaonly properties
property $x { getMethod }
or
property $x { getMethod, null }
and writeonly propeties :)
property $x { null, setMethod }
If someone touch undeclared property and class don't have __get/__set
Zend engine can raise exception ... It's good way? I don't know.
--
Ondrej Ivanic
(ondrej@kmit.sk)
Derick Rethans wrote:
class. The magic methods are responsibly for:
- checking if the property actually "exists"
This is something I wouldn't encourage as one of the virtues of fully
dynamic languages is the "lack" of checking this. Otherwise what happens
if e.g. one inherits such a class to extend it? Does it have to know
about the get/set methods and the necessary declaration of attributes?
And as far as "magic" fields are concerned: IMHO the currently available
mechanism of checking the property name against a (possibly e.g. from a
DB dynamically created) array in the object is sufficient.
So personally I'd not add a language feature as it adds complexity with
little (or arguable) gain.
My $.02,
- Chris
My concern with the self::isVirtual() syntax would be...
class Base {
function __get($name) {
if (!self::isVirtual($name))
throw;
}
}
class Foo {
abstract public $bar = 1;
}
$f = new Foo;
echo $f->bar;
... Are these 'virtual' members going to work like static members, in that using
self:: in a base class doesn't allow access to those static members of
inheriting classes? ie, will the above example throw an error or not, like it
would if a similar thing with statics were to try and be done.
Derick Rethans wrote:
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;
?
Hi,
As for the first question of how to document virtual properties, I have
been recommending that users do this textually inside the docblock for
__get()/__set(). This is actually ideal in almost every case, as anyone
using __get()/__set() for finite, concrete properties should almost
definitely be instead using plain old properties. I wonder if adding
this language feature might be a bit too hopeful. For instance, most
implementations I have seen of __get()/__set() use them because it isn't
possible to know the names of the variables in advance. Simplexml and
ext/soap are great examples of extensions that were they implemented in
userspace would not be able to use the abstract/virtual keyword proposed
because until the specific class is instantiated, one can't know what
they will be working with. The Savant template engine may use them for
grabbing filtered variables in the future, another good example of "you
must document this with prose, not with program syntax".
Having said this, if the proposal continues, I do have some suggestions.
<?php
class Base
{
abstract public $x = 1;
function __get($name)
{
if (!$this->isAbstract($name))) {
/* throw error */
}
}
}
?>
or
<?php
class Base
{
virtual public $x = 1;
function __get($name)
{
if (!$this->isVirtual($name))) {
/* throw error */
}
}
}
?>
I prefer the 2nd, as it will not confuse with abstract classes (and it
will definitely confuse users if we start mixing metaphors
programmatically).
I also prefer $this-> to self:: as it will allow (as James Crumpton
raised) inheritance without redefinition of __get()/__set().
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 statementIf 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.
It seems to me the best solution would be to allow error to be set to
false or an exception object, which would be then thrown as if it was on
the offending line. This would allow the user to customize the error
message as well as the line/file.
Greg
Hello Greg,
Wednesday, August 3, 2005, 4:56:26 AM, you wrote:
Hi,
As for the first question of how to document virtual properties, I have
been recommending that users do this textually inside the docblock for
__get()/__set(). This is actually ideal in almost every case, as anyone
using __get()/__set() for finite, concrete properties should almost
definitely be instead using plain old properties. I wonder if adding
this language feature might be a bit too hopeful. For instance, most
implementations I have seen of __get()/__set() use them because it isn't
possible to know the names of the variables in advance. Simplexml and
ext/soap are great examples of extensions that were they implemented in
userspace would not be able to use the abstract/virtual keyword proposed
because until the specific class is instantiated, one can't know what
they will be working with. The Savant template engine may use them for
grabbing filtered variables in the future, another good example of "you
must document this with prose, not with program syntax".
How about lazy initialization? You cannot have a declared property for those
atm.
Having said this, if the proposal continues, I do have some suggestions.
<?php
class Base
{
abstract public $x = 1;
function __get($name) { if (!$this->isAbstract($name))) { /* throw error */ } }
}
?>>
or
<?php
class Base
{
virtual public $x = 1;
function __get($name) { if (!$this->isVirtual($name))) { /* throw error */ } }
}
?>>
I prefer the 2nd, as it will not confuse with abstract classes (and it
will definitely confuse users if we start mixing metaphors
programmatically).
You would need to add another keyword for no reason.
I also prefer $this-> to self:: as it will allow (as James Crumpton
raised) inheritance without redefinition of __get()/__set().
I prefer here using property_is_virtual($this, $name).
- 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 statementIf 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.
It seems to me the best solution would be to allow error to be set to
false or an exception object, which would be then thrown as if it was on
the offending line. This would allow the user to customize the error
message as well as the line/file.
I suggested exceptions but they are not always acceptable and overcomplicate
many things too much and finally come with some danger.
Best regards,
Marcus
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
}
?>
The whole point of these "virtual" properties is that their names can
be parameterized. If you have 1000 of these variables (in a DB or
somewhere), how would you declare them as "abstract" or "virtual"?
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;
?>
How about a __have_prop() method that you can call to find out if a
certain virtual property exists?
-Andrei
I wonder if it wouldnt be enough to be able to force the triggering of
__set(), __get() for all properties be enough to deal with your situation?
regards,
Lukas
I wonder if it wouldnt be enough to be able to force the triggering of
__set(), __get() for all properties be enough to deal with your situation?
No, besides that would break BC, it would also not solve the problem of
returning errors correctly.
Derick
Derick Rethans wrote:
I wonder if it wouldnt be enough to be able to force the triggering of
__set(), __get() for all properties be enough to deal with your situation?No, besides that would break BC, it would also not solve the problem of
returning errors correctly.
I said "be able to" and not that this should become the norm.
So you would be able to flag an object to behave in this way. Heck this
flag could be "allow now virtual properties, and trigger __set()/__get()
always and throw the proper error otherwise".
regards,
Lukas
The whole point of these "virtual" properties is that their names can be
parameterized. If you have 1000 of these variables (in a DB or somewhere), how
would you declare them as "abstract" or "virtual"?
Then you don't do it - it's not a requirement... just an optional thing
(and ofcourse you can't do the __have_prop() thing then that you
suggested below.
This is ofcourse overly complicated. A better workable solution would be -
without breaking BC (suggestions for syntax here are very welcome):
[snip]
How about a __have_prop() method that you can call to find out if a certain
virtual property exists?
Works for me, but it needs to be able to called statically (::) and
dynamically (->).
Derick
DR>>> How about a __have_prop() method that you can call to find out if a certain
DR>>> virtual property exists?
DR>>
DR>>Works for me, but it needs to be able to called statically (::) and
DR>>dynamically (->).
I must be missing something, because I don't understand one simple thing:
if you need mechanism that would allow you classes to know which
properties they have, and you need custom logic to decide which properties
exist, why don't you write an interface that has WhatAreMyProperties
method and implement it in your classes and use it? Why bother with RFCs
and all __magic stuff?
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/ +972-3-6139665 ext.115
Then you don't do it - it's not a requirement... just an optional thing
(and ofcourse you can't do the __have_prop() thing then that you
suggested below.
Why not? _have_prop() should be able to return true if the class does
handle one of those 1000 properties. They don't need to be declared.
Works for me, but it needs to be able to called statically (::) and
dynamically (->).
Shouldn't be a problem, should it?
-Andrei
Then you don't do it - it's not a requirement... just an optional thing
(and ofcourse you can't do the __have_prop() thing then that you
suggested below.Why not? _have_prop() should be able to return true if the class does handle
one of those 1000 properties. They don't need to be declared.
Ah,you meant that __have_prop() should always return the full array of
things that are supported. That is fine, as long as we can have this
generated from the "abstract" properties that people declared (so that
they can be documented properly too).
Works for me, but it needs to be able to called statically (::) and
dynamically (->).Shouldn't be a problem, should it?
Nope.
Derick
Ah,you meant that __have_prop() should always return the full array of
things that are supported. That is fine, as long as we can have this
generated from the "abstract" properties that people declared (so that
they can be documented properly too).
No, I meant that prototype for _have_prop() would be:
bool function _have_prop(string $propname)
_have_prop() should only care about "virtual" properties anyway. You
pass it a property name, it tells you whether it is a virtual one or
not.
-Andrei
Derick Rethans wrote:
Problems:
- There is no way to document the 'virtual' properties with any of the existing
documentation tools (such as phpdoc and doxygen)
Rather then adding abstract properties, why not simply document the
possible values inside the doc comments ala:
/**
- @var abstract int Contains all X
*/
- 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).
That's the whole concept behind the feature, if the values were known
you may as well use clearly declared property and method names.
- 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.
How about adding a 3rd optional argument to __get and __set which would
be an array of acceptable values for the "name" parameter? If there is a
mismatch a standard warning message will be raised if this parameter was
supplied.
ilia
Derick Rethans wrote:
Problems:
- There is no way to document the 'virtual' properties with any of the
existing
documentation tools (such as phpdoc and doxygen)Rather then adding abstract properties, why not simply document the possible
values inside the doc comments ala:
/**
- @var abstract int Contains all X
*/
That would work, if __set and __get were also called for declared
properties... but they don't do that so you need some keyword - or break
BC.
- 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).That's the whole concept behind the feature, if the values were known you may
as well use clearly declared property and method names.
True, unless you want to force all property access to go through a
setter/getter for all declared properties for checks. This is also
useful for catching typoes:
<?php
error_reporting(4095);
class foo {
public $foo;
}
$obj = new foo;
$obj->fo = 42;
?>
does not throw any notice now for BC reasons.
- 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.How about adding a 3rd optional argument to __get and __set which would be an
array of acceptable values for the "name" parameter? If there is a mismatch a
standard warning message will be raised if this parameter was supplied.
How does the engine know which list is allowed? The engine is calling
the __set and __get methods, not users. The whole idea of using a
keyword here is to provide the engine with such a list.
Derick
I got a quick tutorial from Derick :-) on what precisely will be the
affect on the requested functionality and the suggestion makes a whole
lot of sense. As "weird" declaring virtual properties it seems, there is
really no other alternative for solving the outlined problems in a
consistent manner.
Ilia
Hi!
Sorry for wrong threading or if this solution was suggested before... i
currently don't have access to my mail client:)
- 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.
Don't know if this can be implemented... but what's about a 3rd boolean
"handled" call-by-reference-parameter which must be switched to "TRUE" if
the property could be handled? Should be TRUE
if ommitted for bc reasons,
of course.
greets, Roland
- 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.Don't know if this can be implemented... but what's about a 3rd boolean
"handled" call-by-reference-parameter which must be switched to "TRUE" if
the property could be handled? Should beTRUE
if ommitted for bc reasons,
of course.
That was my original idea.
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
The way ActionScript 2.0 solves this is with set and get keywords on
function declarations. Any class can contain as many setter/getters as
they need,. Since we dont want to introduce any new keywords how about
something similar with __set and __get?
<?php
class Foo
{
private $_fooProp;
function __set fooProp($val)
{
$this->_fooProp = $val; // $_fooProp is read only
}
function __set barProp($val)
{
// logic to set barProp...
}
function __get barProp($val)
{
// 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:
- There is no way to document the 'virtual' properties with any of the existing
documentation tools (such as phpdoc and doxygen)- 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).- 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 statementIf 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
...And, this could allow static member overloading as well!
-Justin
Justin Hannus wrote:
The way ActionScript 2.0 solves this is with set and get keywords on
function declarations. Any class can contain as many setter/getters as
they need,. Since we dont want to introduce any new keywords how about
something similar with __set and __get?<?php
class Foo
{
private $_fooProp;function __set fooProp($val) { $this->_fooProp = $val; // $_fooProp is read only } function __set barProp($val) { // logic to set barProp... } function __get barProp($val) { // 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:
- There is no way to document the 'virtual' properties with any of
the existing
documentation tools (such as phpdoc and doxygen)- 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).- 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 statementIf 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
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:
- There is no way to document the 'virtual' properties with any of
the existing
documentation tools (such as phpdoc and doxygen)- 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).- 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 statementIf 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
The way ActionScript 2.0 solves this is with set and get keywords on function
declarations. Any class can contain as many setter/getters as they need,.
Since we dont want to introduce any new keywords how about something similar
with __set and __get?
[...]
To allow for BC, if there is no identifier after the __set/__get then the
existing rules apply.
This is all way to complex.
Derick
Problems:
- There is no way to document the 'virtual' properties with any of
the existing
documentation tools (such as phpdoc and doxygen)
This sounds like a tool problem, not a language problem.
- 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).
Sometimes you just want to know if a single property exists and
sometimes you want to know all the properties. There are cases where
generating the full list of properties may be overly expensive (ORM
with inheritance).
__has_property($name)
__get_property_list()
Note that some properties may be read only and some might be write
only, so perhaps incorporating intended use into the API:
__has_readable_property($name)
__has_writable_property($name)
__get_readable_properties()
__get_writable_properties();
- 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.
I would rather see exceptions used instead of changing the established
method signature of __get and __set. What about defining a standard
PropertyNotFound exception?
While on the topic, a little wishlisting. i would like to see an
accessor method search path, much like Objective C's KeyValueCoding:
http://developer.apple.com/documentation/Cocoa/Conceptual/
KeyValueCoding/index.html
so, this defines a read only virtual property:
class Square {
function __get_area() {
return $this->width*$this->length;
}
}
echo $sq->area;
in this case, PHP would look for a __get_XXX method before calling the
__get as a last resort fallback. I'm not attached to this particular
syntax, but I think the KVC concept with an accessor method naming
convention has proven worthwhile in Objective C. KVC also has some
interesting advanced features such as indexed properties, paths, change
notification, and constraint enforcement. KVC is worth emulating.
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.
I updated the proposal:
http://files.derickrethans.nl/property_overloading.html
If nobody as any better idea on how to solve it I'd like to start
implementing it.
Derick
-- Derick Rethans eZ systems | http://ez.no
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.I updated the proposal:
http://files.derickrethans.nl/property_overloading.htmlIf nobody as any better idea on how to solve it I'd like to start
implementing it.Derick
-- Derick Rethans eZ systems | http://ez.no
--
This seems to be a good propals. IMO, it lacks just one thing - what
about property with a pulbic getter and protected setter for example?
Derick Rethans wrote:
I updated the proposal:
http://files.derickrethans.nl/property_overloading.htmlIf nobody as any better idea on how to solve it I'd like to start
implementing it.
I seem to remember that we had some voices here stating that the current
mechanisms are sufficient. Adding new keywords and/or new magic methods
is something which should have a very high threshold as it complicates
the language.
To me the proposal looks like a worst of both worlds kind of compromise:
Add new keywords and magic methods coupled with (ab)using the (in this
context somewhat inelegant) __get/__set mechanism.
So I'd rather not see this implemented to be honest.
- Chris
Christian Schneider wrote:
Derick Rethans wrote:
I updated the proposal:
http://files.derickrethans.nl/property_overloading.htmlIf nobody as any better idea on how to solve it I'd like to start
implementing it.I seem to remember that we had some voices here stating that the current
mechanisms are sufficient. Adding new keywords and/or new magic methods
is something which should have a very high threshold as it complicates
the language.To me the proposal looks like a worst of both worlds kind of compromise:
Add new keywords and magic methods coupled with (ab)using the (in this
context somewhat inelegant) __get/__set mechanism.So I'd rather not see this implemented to be honest.
I could not agree more!
Edin
Derick Rethans wrote:
I updated the proposal:
http://files.derickrethans.nl/property_overloading.htmlIf nobody as any better idea on how to solve it I'd like to start
implementing it.I seem to remember that we had some voices here stating that the current
mechanisms are sufficient. Adding new keywords and/or new magic methods is
something which should have a very high threshold as it complicates the
language.
If you would have properly read the proposal you see that there are 3!
problems with it. And instead of whining about things, I actually spend
some time of contributing with patches too.
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....
regards,
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
Derick Rethans wrote:
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....
I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.
Edin
Derick Rethans wrote:
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.
Right, I agree with that. But now we have a __get/__set thing that has
inherent flaws, and I'd like to see the OO crap that we have working in
a useful way.
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
At 06:00 AM 8/25/2005, Edin Kadribasic wrote:
Derick Rethans wrote:
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.
I completely agree.
This very much bloats the language syntax and would be mainly there
for the sake of OO fanatics. Guys, seriously, this kind of stuff and
a lot of the other OO proposals I've heard here lately are going to
lead to PHP going down the drain. Derick, the fact that you say it's
not worse than "other OO crap that people are suggesting here...."
just means that it's also good to leave the other crap out of PHP.
Sometimes I really wished people who really need this kind of crap go
and download Python & Smalltalk, instead of killing PHP's benefits.
There is no language that does everything, and I'd like to keep PHP
good at what it does best. People who aren't content with PHP not
being a master piece in object oriented really should look elsewhere.
I'll be happy to hear back from them regarding development time,
ease-of-use and training period for developers.
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples... As far as
documentation is concerned, you'll usually have a nice array in the
beginning of the class declaration which is pretty verbose, if that's
not good enough people can use phpDoc (or we can enhance phpDoc). If
you strongly feel that something like _have_prop() is needed despite
exceptions doing the job, it's something that could be considered but
I'm not convinced it's needed.
Andi
At 06:00 AM 8/25/2005, Edin Kadribasic wrote:
Derick Rethans wrote:
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.I completely agree.
This very much bloats the language syntax and would be mainly there for the
sake of OO fanatics. Guys, seriously, this kind of stuff and a lot of the
other OO proposals I've heard here lately are going to lead to PHP going down
the drain. Derick, the fact that you say it's not worse than "other OO crap
that people are suggesting here...." just means that it's also good to leave
the other crap out of PHP.
I'm just arguing that the current way that setters and getters are
implemented is broken. Instead of keeping a broken behavior I would like
to see it fixed.
I don't see why the __get/__set/__isset/__unset methods themselves can't check
if the property exists and throw an exception if it doesn't.
It has more to do with problems with encapsulation and visibility.
Frederik made a nice summary of that, he will reply here:
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
I don't think __call/__get/__set should be resolving visibility.
Maybe that's the difference. It's main purpose is to allow exposing a
dynamic public interface.
I understand exactly where he was going with this, and I just don't
think PHP is the right place to do it.
Andi
At 02:55 AM 8/26/2005, Derick Rethans wrote:
At 06:00 AM 8/25/2005, Edin Kadribasic wrote:
Derick Rethans wrote:
And how can you possibly argue that this more complex than
all the other
OO crap that people are suggesting here....I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.I completely agree.
This very much bloats the language syntax and would be mainly there for the
sake of OO fanatics. Guys, seriously, this kind of stuff and a lot of the
other OO proposals I've heard here lately are going to lead to
PHP going down
the drain. Derick, the fact that you say it's not worse than "other OO crap
that people are suggesting here...." just means that it's also
good to leave
the other crap out of PHP.I'm just arguing that the current way that setters and getters are
implemented is broken. Instead of keeping a broken behavior I would like
to see it fixed.I don't see why the __get/__set/__isset/__unset methods
themselves can't check
if the property exists and throw an exception if it doesn't.It has more to do with problems with encapsulation and visibility.
Frederik made a nice summary of that, he will reply here:Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
I'm just arguing that the current way that setters and getters are
implemented is broken. Instead of keeping a broken behavior I would
like
to see it fixed.
Derick,
It is not broken its incomplete. PHP doesn't really have an
implementation of getters and setters. The __get and __set are really
just "property not defined" hooks, not getters and setters (accessor
methods).
If you take a look at a dynamic language that does does define a
standard for getters and setters, Key Value Coding in Objective C, you
will see what I mean. KVC defines a (complicated) search path for
looking up a property:
- Search the receiver’s class for an accessor method whose name
matches the pattern -get<Key>, -<key>, or -is<Key>, in that order. - If no accessor is found, and the receiver’s class method
accessInstanceVariablesDirectly returns YES, the receiver is searched
for an instance variable whose name matches the pattern _<key>,
_is<Key>, <key>, or is<Key>, in that order. - If no appropriate accessor or instance variable is found,
valueForUndefinedKey: is invoked for the receiver, and the value is
returned.
ObjectiveC's valueForUndefinedKey is the same as PHP's __get. What php
lacks is the stage in the process that looks for accessor methods. In
current PHP:
- Search the object for an instance variable <key>
- If no instance variable is found, __get is invoked on the object and
the value returned.
I think where you are running into trouble with the property keyword is
that it is targeting the wrong stage in the property name search
process. It simply does not make sense to declare properties in the
class for the "undefined property" (__get) stage of the search process.
Right now, most people simulate accessor methods in user space using
__get and __set and if statements, case statements, introspection,
arrays, or a variety of other techniques.
If you want to improve this process and bring it into the engine, then
the place to do it is the property name search path. This is where
declared properties with accessor methods should be handled. An
accessor method check could be added either before or after the check
for the instance variable. A new keyword isn't necessary here, a
simple naming convention could suffice as in ObjectiveC. Reflection
could be made aware of the naming conventions, etc.
However, adding the stage before, as in ObjectiveC, seems unlikely to
gain much support here because of potential BC issues with method names
and performance concerns. (Although, some things will become faster,
some things will become slower.)
Adding the stage after also seems unlikely to gain much support here
because it can be simulated fairly well right now in user space using
the current __get mechanisms. (Which is exactly what we do on the WACT
project.)
I happen to think that a PHP standard for accessor methods would be a
good thing, but adding a stage to the search path is a hard sell.
Without adding a stage to the search path for property names, a
property keyword such as proposed makes little sense, the current
mechanisms are sufficient.
I understand the problem you're trying to solve, support the need for a
solution, but don't think this proposal solves the problem.
Ref:
http://developer.apple.com/documentation/Cocoa/Conceptual/
KeyValueCoding/index.html
It has more to do with problems with encapsulation and visibility.
Frederik made a nice summary of that, he will reply here:
Ok, here goes:
The way I see it properties in PHP should do the following:
- Make it possible to override behavior when accessing properties
- easy access to properties (through -> for example)
- make it possible to give constructive feedback when programmers uses
a property in the wrong way - Well defined control over when setters and getters are used and when
they are not. - The possibility to use the normal visibility rules as for other class
variables.
Now, the __set and __get functionality almost conform to the above
requirements. 1 & 2 are already covered, AFAIK 3 has been discussed and
a good solution has been found to this. The only problems we have left
are 4 and 5.
Let me illustrate problem 4 with an example:
class A {
private variable; // some property
public function test() {
$this->variable = 42;
}
}
In this case the variable would be set directly in the test method. This
is not desirable since it is unclear when the setters and getters are
called and when you are actually setting the variable directly or not.
Basically you want the setters and getters to be run except when
explicitly setting the variables. This problem becomes even more
evident in the following example:
class A {
protected variable; // some property
}
class B extends A {
public function test() {
$this->variable = 42;
}
}
In this example the variable would still be set directly (not using the
set and get methods). Using the current implementation you could fix
this case by setting the variable to private. This brings us to the
next issue: using the current implementation it is not possible to have
private or protected properties.
class A {
private variable; // some property
public function test() {
$this->variable = 42;
}
}
As you can see, the variable (in fact) is not private at all. It is
public. Hence there is a mismatch between what you declare and what it
actually is. Setting a property to be public doesn't make sense at all
since the __set and __get function will not be called then.
Here is a possible way to solve these two interconnected problems:
class A {
private property priv_prop;
protected property prot_prop;
public property pub_prop;
// very simplified implementation
function __set( $name, $value ){
$this->properties[$name] = $value;
}
public function test() {
// private property, we have access
$this->priv_prop = 42;
}
}
function somewhere() {
$a = new A();
// private property, not allowed
$a->priv_prop = 42;
// public property.. ok
$a->pub_prop = 42;
}
The way this works is that when a property is declared the __set and
__get is always run when accessing it unless you don't have access to
that property of course.
Similarly you could also use the protected property in subclasses. Using
an implementation like this, the property keyword does nothing but
declare the existence of a property with this name. The actual storage
of the property data must be done somewhere else, e.g in a private
member variable. It would of course be even better if the property
declaration also declared a variable. However, then we need an explicit
way of setting them since we still want __set and __get to be called
for private properties.
In addition to solving both problems this solution with explicit
property declaration also makes it easy to document the properties of a
class.
Cheers,
Frederik
Frederik Holljen
Head of development
fh@ez.no | eZ systems | ez.no
Hello Andi,
Friday, August 26, 2005, 3:39:08 AM, you wrote:
At 06:00 AM 8/25/2005, Edin Kadribasic wrote:
Derick Rethans wrote:
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....I belive that we should do our best to filter out this storm of OO
feature requests. People want to make PHP look like some other OO
languages for no good reason other that they're familiar with it or that
their CS teacher thought they were cool.
I completely agree.
This very much bloats the language syntax and would be mainly there
for the sake of OO fanatics. Guys, seriously, this kind of stuff and
a lot of the other OO proposals I've heard here lately are going to
lead to PHP going down the drain. Derick, the fact that you say it's
not worse than "other OO crap that people are suggesting here...."
just means that it's also good to leave the other crap out of PHP.
Sometimes I really wished people who really need this kind of crap go
and download Python & Smalltalk, instead of killing PHP's benefits.
There is no language that does everything, and I'd like to keep PHP
good at what it does best. People who aren't content with PHP not
being a master piece in object oriented really should look elsewhere.
I'll be happy to hear back from them regarding development time,
ease-of-use and training period for developers.
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples...
Interesting, How do you do that? There is no __isset or __unset.
As far as
documentation is concerned, you'll usually have a nice array in the
beginning of the class declaration which is pretty verbose, if that's
not good enough people can use phpDoc (or we can enhance phpDoc). If
you strongly feel that something like _have_prop() is needed despite
exceptions doing the job, it's something that could be considered but
I'm not convinced it's needed.
Andi
Best regards,
Marcus
At 11:32 AM 8/26/2005, Marcus Boerger wrote:
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples...Interesting, How do you do that? There is no __isset or __unset.
Did you check HEAD?
Andi
Hello Andi,
Saturday, August 27, 2005, 12:52:38 AM, you wrote:
At 11:32 AM 8/26/2005, Marcus Boerger wrote:
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples...Interesting, How do you do that? There is no __isset or __unset.
Did you check HEAD?
When did this get sneaked in and why? And why didn't we make it like
ArrayAccess with interfaces? And was this even being discussed and i
was sleeping?
I see dmitry did it:
$ cvs log -r1.288 Zend/zend.h
date: 2005/07/07 16:07:08; author: dmitry; state: Exp; lines: +5 -1
Fixed bug #33512 (Add missing support for isset()/unset() overloading to complement the property get/set methods)
Best regards,
Marcus
At 04:27 PM 8/26/2005, Marcus Boerger wrote:
Hello Andi,
Saturday, August 27, 2005, 12:52:38 AM, you wrote:
At 11:32 AM 8/26/2005, Marcus Boerger wrote:
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples...Interesting, How do you do that? There is no __isset or __unset.
Did you check HEAD?
When did this get sneaked in and why? And why didn't we make it like
ArrayAccess with interfaces? And was this even being discussed and i
was sleeping?I see dmitry did it:
$ cvs log -r1.288 Zend/zend.h
date: 2005/07/07 16:07:08; author: dmitry; state: Exp; lines: +5 -1
Fixed bug #33512 (Add missing support for isset()/unset()
overloading to complement the property get/set methods)
I asked Dmitry to fix this as it seemed kind of buggy to me (bug
#33512). Thought everyone saw it.
It's not in an interface because __get/__set were introduced before
interfaces existed....
Andi
Hello Andi,
Saturday, August 27, 2005, 1:45:43 AM, you wrote:
At 04:27 PM 8/26/2005, Marcus Boerger wrote:
Hello Andi,
Saturday, August 27, 2005, 12:52:38 AM, you wrote:
At 11:32 AM 8/26/2005, Marcus Boerger wrote:
I don't see why the __get/__set/__isset/__unset methods themselves
can't check if the property exists and throw an exception if it
doesn't. I always do that in all my examples...Interesting, How do you do that? There is no __isset or __unset.
Did you check HEAD?
When did this get sneaked in and why? And why didn't we make it like
ArrayAccess with interfaces? And was this even being discussed and i
was sleeping?I see dmitry did it:
$ cvs log -r1.288 Zend/zend.h
date: 2005/07/07 16:07:08; author: dmitry; state: Exp; lines: +5 -1
Fixed bug #33512 (Add missing support for isset()/unset()
overloading to complement the property get/set methods)
I asked Dmitry to fix this as it seemed kind of buggy to me (bug
#33512). Thought everyone saw it.
It's not in an interface because __get/__set were introduced before
interfaces existed....
Ah yes, makes quite sense then and we're consistent for properties and array
acccess though we don't use the same technology for them.
Best regards,
Marcus
Derick Rethans wrote:
If you would have properly read the proposal you see that there are 3!
problems with it. And instead of whining about things, I actually spend
some time of contributing with patches too.
Let's agree to disagree. I easily work around these 3 "problems" here,
so my patch would be empty.
I know that I'm not contributing code, only my personal point of view
and that's why I won't start crying if you guys decide to add properties
to PHP. I just had the feeling that the discussion was never really
properly decided, even amongst the core people on this list. Don't
worry, I won't write any more follow-ups after this :-)
And how can you possibly argue that this more complex than all the other
OO crap that people are suggesting here....
I'm all with you there, I don't like that fancy OO crap either ;-)
- Chris
DR>>If nobody as any better idea on how to solve it I'd like to start
DR>>implementing it.
Some questions about the RFC:
- What exactly property public $x = 1; means? I.e., first of all, what
"1" means - does it mean that __get guarantees to return 1 on __get("x")
if it was never set? Should PHP somehow take care of that or is it
responsibility of __get writer? How PHP should act on this - should it
define entry in the hashtable or should it just ignore it? What
protected/private means there too? Would PHP have to take care for
inheritance and if so - how will it be enforced so that __get can't be
called for protected property?
Altogether, problem (1) by itself has much easier solution - just add a
keyword (or fix existing keywords) to phpdoc/doxygen allowing to document
the thing without having language construct for it. I don't see why would
phpdoc require PHP engine support concept of virtual property in order to
document it. Afeter all, people routinely document code before even
writing it ;)
-
I don't like having to go to reflection for finding out if it's defined
or not. Also, would __have_prop be overridable and how it is different
from __isset existing now? If it's overridable, I don't see why PHP engine
needs anything to do with it - you always can write a method
and name it __have_prop and call it :) If it's not - you will be asked to
make it overridable almost instantly. So again I'm not sure what would be
PHP support for this thing. -
I recognise that there is a problem with __handlers diagnostics, but I
don't see how returning true/false would help you - you wan't know what
failure 'false' means still - what if there's another failure besides
property not existing in __handler?
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/ +972-3-6139665 ext.115
DR>>If nobody as any better idea on how to solve it I'd like to start
DR>>implementing it.Some questions about the RFC:
- What exactly property public $x = 1; means? I.e., first of all, what
"1" means - does it mean that __get guarantees to return 1 on __get("x")
if it was never set?
Uh? It's just a default value, which I now remember we can't do. So
forget the " = 1" ;-)
Altogether, problem (1) by itself has much easier solution - just add a
keyword (or fix existing keywords) to phpdoc/doxygen allowing to document
the thing without having language construct for it. I don't see why would
phpdoc require PHP engine support concept of virtual property in order to
document it. Afeter all, people routinely document code before even
writing it ;)
Problem 1 is the least of the 3 problems, but introducing the keyword
also helps solving the other two.
- I don't like having to go to reflection for finding out if it's defined
or not.
Me neither, that's why I wrote it was a bad solution in the proposal ;-)
Also, would __have_prop be overridable and how it is different
from __isset existing now? If it's overridable, I don't see why PHP engine
needs anything to do with it - you always can write a method
and name it __have_prop and call it :) If it's not - you will be asked to
make it overridable almost instantly. So again I'm not sure what would be
PHP support for this thing.
If I'm not wrong, __isset() checks if something is set not if it's
available. The reason for __have_prop() is to check whether something is
declaread as "property" in the class. There is no other way of doing
that unless we'd like to break BC.
- I recognise that there is a problem with __handlers diagnostics, but I
don't see how returning true/false would help you - you wan't know what
failure 'false' means still - what if there's another failure besides
property not existing in __handler?
If it returns false, the engine can throw an error on the line where it
was used, not inside the __get() method itself, as that doesn't help
debugging your code (as you don't usually know where it was called
from).
Derick
--
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org
DR>>Problem 1 is the least of the 3 problems, but introducing the keyword
DR>>also helps solving the other two.
Strangely enough it is the agument I happen to hear most. I think it's not
PHP problem at all.
DR>>If I'm not wrong, __isset() checks if something is set not if it's
DR>>available. The reason for __have_prop() is to check whether something is
DR>>declaread as "property" in the class. There is no other way of doing
DR>>that unless we'd like to break BC.
That, however, does not answer my second question - when __have_prop would
be called by the engine and if never, what prevents you from calling any
method __have_prop just now?
DR>>If it returns false, the engine can throw an error on the line where
DR>>it was used, not inside the __get() method itself, as that doesn't
DR>>help debugging your code (as you don't usually know where it was
DR>>called from).
That I understand. However, you still don't have means to know what
was wrong in this line. BTW, how comes you don't know where it came from
if you have backtrace?
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/ +972-3-6139665 ext.115
Stanislav Malyshev wrote:
DR>>If it returns false, the engine can throw an error on the line where
DR>>it was used, not inside the __get() method itself, as that doesn't
DR>>help debugging your code (as you don't usually know where it was
DR>>called from).That I understand. However, you still don't have means to know what
was wrong in this line. BTW, how comes you don't know where it came from
if you have backtrace?
Uhm Derick has said multiple times that he can get a backtrace, but that
backtrace points at the wrong place just as manually triggering an
error. Obviously this is somehow fixable with alot of magic inside a
custom error handler. However I think the addition Derick is proposing
is fairly reasonble and clear and doesnt introduce a new keyword or
magic method.
regards,
Lukas
I updated the proposal:
http://files.derickrethans.nl/property_overloading.html
#1)
It seems to me that after declaring the property with the property
keyword, the property isn't so virtual anymore.
#2)
I think this is a good idea, but aren't double underline methods
reserved for those called by PHP itself. The example shows the user
calling __have_prop(). Under what circumstances would php call
__have_prop()?
#3)
I would rather see an exception based mechanism for this, but I'll
concede that as unlikely, so i'll just suggest using the standard PHP
boolean values. The proposal implies TRUE
& NULL
would be the same,
which seems inconsistent.
Hello Derick,
Thursday, August 25, 2005, 2:01:56 PM, you wrote:
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.
I updated the proposal:
http://files.derickrethans.nl/property_overloading.html
If nobody as any better idea on how to solve it I'd like to start
implementing it.
Instead of "__have_prop" can you make that "__has_prop" or "__exists" or
"__declared". "have" simply seems wrong thus (2). However that uses two
words which i don't like and so i cam to (3) and (4). Version (3) is better
than (4) because ArrayAccess also uses "exists".
Best regards,
Marcus
Derick Rethans wrote:
I updated the proposal:
http://files.derickrethans.nl/property_overloading.html
-
seems to be an issue in doxygen and phpDocumentor
-
this seems solveable with a non public set of arrays containing
information about the property and its visibility ..
with a bit of hacking phpDocumentor could even read this information if
they/we decide on a suggested nameing standard. i dont see why we should
pollute the php language with this though
- sounds like a great idea. we should also have something like this for
__call().
regards,
Lukas
Hello Derick,
Thursday, August 25, 2005, 2:01:56 PM, you wrote:
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.
I updated the proposal:
http://files.derickrethans.nl/property_overloading.html
If nobody as any better idea on how to solve it I'd like to start
implementing it.
To your solution of problem 3. We do not yet allow signatures of the
form (... [, ...]) since that would break our inheritance system.
The thing you could do is that the root class decides whetehr we have
that optional paramater always or never.
Best regards,
Marcus