Hello,
This is my first time using a mailing list, so please bear with me.
Some time back I suggested that PHP should have a property get/set syntax
similar to that of Microsoft's C# language. One of the PHP developers
suggested that if I were serious about it, I should write an RFC. I have
done just that, and I would now like to present my RFC to everyone here in
internals, in order to start a discussion on the topic.
The RFC:
Many modern languages have a special syntax for writing get/set method
pairs. All that PHP currently supports is __get and __set, which while
great for writing generic get/set methods is nearly useless when it comes
to individual properties. Our only other choice is the age old process of
writing custom class methods to make our get/set methods. Not only does
this lack any kind of uniformity, but it also complicates the syntax
($foo->getBar() and $foo->setBar('baz') instead of $foo->bar and
$foo->bar='baz'). I believe that if PHP is going embrace modern
object-oriented design, including encapsulation, than it needs a modern
solution to property getters and setters.
I wont add much more here, but rather let the RFC itself do the talking.
It is fairly well fleshed out, and should explain everything clearly
enough.
Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntax
Thanks,
Dennis Robinson
Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntaxThanks,
Dennis Robinson
This is a very well-written and well-thought through RFC, Dennis. Nicely
done.
That said, I am not yet convinced. :-)
First of all, I have generally found the Bean-style getter/setter approach to
be a sign of poor encapsulation to begin with. You shouldn't be mucking with
internal elements of an object in the first place, period. More details on
that here:
http://www.garfieldtech.com/blog/property-visibility
However, I do see a potential use here if "properties" are treated
conceptually as an entirely new concept and not as an indirection layer for
class properties. That would make them more akin to a class that has both
methods and also implements ArrayAccess for "properties of the conceptual
object, that may not have anything to do with internal class members."
Viewed from that angle, I would have the following comments:
-
I strongly prefer the first syntax over the second. The "property" keyword
improves readability, and the closing semi-colon is going to be forgotten on a
daily basis. I still forget sometimes when to use it and when not to when
writing Javascript. :-) I cannot speak to the engine complexity involved but
from a PHP-autor point of view I believe the first syntax is much easier to
use. -
The use of identical syntax for class members and properties could create
confusion as to which is which. One could argue that is the point, but only
if we view properties as "just" an indirection layer around the physical class
members, which as I noted above I believe is a poor architectural design.
There may not be an alternative here, but I mention it for completeness. -
I concur with the RFP's preference for "implicit write-only" properties
rather than explicit, as it seems more flexible. -
The layering of accessibility keywords I find intriguing, in a mostly good
way. That can offer a great deal of flexibility to control who can do what
when. However, I am concerned about the confusion possible in the following:
public property Hours {
get { return $this->seconds / 3600; }
protected set { $this->seconds = $value * 3600; }
}
The set method is then scoped with two different visibility directives: public
and protected. Which applies? Since both are optional (presumably) I can see
a potential here for confusion, especially if you also start mentioning
keywords like final. This should be made more definitive if possible.
-
If interfaces can declare properties (niiice), Traits should be able to
provide them. That provides full parallelism with methods, which I believe
developers will expect. -
I am curious what the performance implication would be. For instance, I've
benchmarked both magic property access (__get()) and ArrayAccess to be around
4 times as slow as accessing a class member.
http://www.garfieldtech.com/blog/benchmarking-magic
Since in essence what is happening here is binding a function to fire when a
class member is accessed (given the identical syntax), I'm concerned that
there would be a similar performance issue. A 4x slower performance cost
would make me avoid properties in favor of class members unless I absolutely
needed them. A 2x or less I could see making more use of.
- Which also brings up an interesting question:
class Foo {
public $a = 1;
protected $b = 2;
public property $a { get { return 3; } }
public property $b { get { return 4; } }
}
$f = new Foo();
print $f->a . PHP_EOL; // Does this print 1 or 3?
print $f->b . PHP_EOL; // Does this print 2 or 4, or error?
I'm sure there's arguments every which way. My preference would be for
properties to always win over class members, followed by the above code sample
being a compile error.
It gets even tricker when you introduce inheritance. If a child class has a
[property|class member] of the same name as a parent's [class member|
property], then what?
That's all I got for now. Once again, nice RFP but still needs some thinking.
--Larry Garfield
hi,
Great job, very well written proposal.
Quick notice: the readonly keyword work without being used with a
method (or the default getter/setter):
class A {
public readonly propro;
}
The writeonly property (useful from time to time) is not supported by
default but using the custom definitions.
I'm all in favour of having that in PHP. However not in an immediate
future (ie 5.4) but the next major version.
Cheers,
Hello,
This is my first time using a mailing list, so please bear with me.
Some time back I suggested that PHP should have a property get/set syntax
similar to that of Microsoft's C# language. One of the PHP developers
suggested that if I were serious about it, I should write an RFC. I have
done just that, and I would now like to present my RFC to everyone here in
internals, in order to start a discussion on the topic.The RFC:
Many modern languages have a special syntax for writing get/set method
pairs. All that PHP currently supports is __get and __set, which while
great for writing generic get/set methods is nearly useless when it comes
to individual properties. Our only other choice is the age old process of
writing custom class methods to make our get/set methods. Not only does
this lack any kind of uniformity, but it also complicates the syntax
($foo->getBar() and $foo->setBar('baz') instead of $foo->bar and
$foo->bar='baz'). I believe that if PHP is going embrace modern
object-oriented design, including encapsulation, than it needs a modern
solution to property getters and setters.I wont add much more here, but rather let the RFC itself do the talking.
It is fairly well fleshed out, and should explain everything clearly
enough.Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntaxThanks,
Dennis Robinson--
--
Pierre
@pierrejoye | http://blog.thepimp.net | http://www.libgd.org
Hi,
I like the idea of the property get/set syntax, but in my opinion it
doesn't figure with PHP's syntax, because it breaks the readability. The
problem for me is the nesting of the inner set and get. How do you
document these syntax.
/**
*/
public $name {
/**
*
*/
get {
return $this->name;
}
/**
*
*/
set {
$this->name = htmlentities($value);
$this->name = strip_tags($this->name);
}
};
What I also miss is the lack of type hinting. As I see it, it isn't
possible with this syntax.
I would prefer the syntax from ActionScript. This is more like the
normal PHP function syntax with an additional set or get keyword.
/**
*/
public function set name(string $name) {
$this->name = htmlentities($name);
$this->name = strip_tags($this->name);
}
/**
*/
public function get name($name) {
return $this->name;
}
Greetings,
Christian
Hello,
This is my first time using a mailing list, so please bear with me.
Some time back I suggested that PHP should have a property get/set
syntax
similar to that of Microsoft's C# language. One of the PHP
developers
suggested that if I were serious about it, I should write an RFC. I
have
done just that, and I would now like to present my RFC to everyone
here in
internals, in order to start a discussion on the topic.The RFC:
Many modern languages have a special syntax for writing get/set
method
pairs. All that PHP currently supports is __get and __set, which
while
great for writing generic get/set methods is nearly useless when it
comes
to individual properties. Our only other choice is the age old
process of
writing custom class methods to make our get/set methods. Not only
does
this lack any kind of uniformity, but it also complicates the syntax
($foo->getBar() and $foo->setBar('baz') instead of $foo->bar and
$foo->bar='baz'). I believe that if PHP is going embrace modern
object-oriented design, including encapsulation, than it needs a
modern
solution to property getters and setters.I wont add much more here, but rather let the RFC itself do the
talking.
It is fairly well fleshed out, and should explain everything clearly
enough.Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntaxThanks,
Dennis Robinson
On Sun, Nov 28, 2010 at 11:48 PM, Christian Kaps
christian.kaps@mohiva.com wrote:
...
/**
*
*/
public function set name(string $name) {
$this->name = htmlentities($name);
$this->name = strip_tags($this->name);
}/**
*
*/
public function get name($name) {
return $this->name;
}Greetings,
Christian
For whatever it's worth, I think that this syntax fits much better
into PHP than do either of the those in the RFC.
Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntaxThanks,
Dennis Robinson
I'd really like this feature to be part of PHP.
I don't particularly like the use of what looks like a closure for the set/get.
I used to code in Delphi and I always like the way in which their
properties were defined.
Essentially, the setter and getter are normal methods which are cherry
picked for a property [1].
<?php
class TimePeriod
{
protected $seconds;
public property Hours read getHours write setHours;
protected function getHours()
{
return $this->seconds / 3600;
}
protected function setHours()
{
$this->seconds = $value * 3600;
}
// This property is read-only
public property Minutes read getMinutes;
protected function getMinutes()
{
return $this->seconds / 60;
}
public property Milliseconds read getMilliseconds write setMilliseconds;
public function getMilliseconds()
{
// This method is public
return $this->seconds * 60;
}
protected function setMilliseconds()
{
// This method is protected
$this->seconds = $value * 3600;
}
}
For me, the advantage here is that I can independently the methods
from the property. If I want to force a subclass to implement a
setter/getter, then I can abstract the function in the base class.
Sure, some may say that I should be using an interface. I disagree as
I probably don't want the methods to be public. Protected or even
private and/or final.
The classic example is one of shapes. Every shape has a public $area
property, but the value would be provided by an abstract protected
TShape::getArea(); method. I can also finalise them, so, for example,
a triangle shape could have a final protected getArea() method and all
sub classes of triangles (scalene, isosceles, equilateral) would not
implement their own getArea() method.
The downside is certainly that the code is more verbose than I would
guess many people would like.
Regards,
Richard.
[1] http://www.delphibasics.co.uk/RTL.asp?Name=Property
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Richard Quadling wrote:
I'd really like this feature to be part of PHP.
I don't particularly like the use of what looks like a closure for the set/get.
I used to code in Delphi and I always like the way in which their
properties were defined.Essentially, the setter and getter are normal methods which are cherry
picked for a property [1].<?php
class TimePeriod
{
protected $seconds;public property Hours read getHours write setHours; protected function getHours() { return $this->seconds / 3600; } protected function setHours() { $this->seconds = $value * 3600; } // This property is read-only public property Minutes read getMinutes; protected function getMinutes() { return $this->seconds / 60; } public property Milliseconds read getMilliseconds write setMilliseconds; public function getMilliseconds() { // This method is public return $this->seconds * 60; } protected function setMilliseconds() { // This method is protected $this->seconds = $value * 3600; }
}
For me, the advantage here is that I can independently the methods
from the property. If I want to force a subclass to implement a
setter/getter, then I can abstract the function in the base class.
Sure, some may say that I should be using an interface. I disagree as
I probably don't want the methods to be public. Protected or even
private and/or final.The classic example is one of shapes. Every shape has a public $area
property, but the value would be provided by an abstract protected
TShape::getArea(); method. I can also finalise them, so, for example,
a triangle shape could have a final protected getArea() method and all
sub classes of triangles (scalene, isosceles, equilateral) would not
implement their own getArea() method.The downside is certainly that the code is more verbose than I would
guess many people would like.Regards,
Richard.
setMilliseconds() should have $value as parameter instead of a magic name.
What about allowing this syntax to attach the property to a variable?
For instance:
<?php
class TimePeriod
{
protected $seconds;
protected $minutes;
protected $hours;
public property Seconds read $seconds write setSeconds;
public property Minutes read $seconds write setMinutes;
public property Hours read $seconds write setHours;
public function setSeconds($seconds)
{
if ($seconds >= 0 && $seconds < 60) $this->seconds = $seconds;
}
public function setMinutes($minutes)
{
if ($minutes >= 0 && $minutes < 60) $this->minutes = $minutes;
}
public function setHours($hours)
{
if ($hours >= 0 && $hours < 24) $this->hours = $hours;
}
}
We only want to perform checks on write, so instead of writing the trivial
getters, the property is set to the variable itself. Child classes could
reattach it to a function if needing more control.
2010/11/29 Ángel González keisial@gmail.com:
Richard Quadling wrote:
setMilliseconds() should have $value as parameter instead of a magic name.What about allowing this syntax to attach the property to a variable?
For instance:
<?php
class TimePeriod
{
protected $seconds;
protected $minutes;
protected $hours;public property Seconds read $seconds write setSeconds;
public property Minutes read $seconds write setMinutes;
public property Hours read $seconds write setHours;public function setSeconds($seconds)
{
if ($seconds >= 0 && $seconds < 60) $this->seconds = $seconds;
}public function setMinutes($minutes)
{
if ($minutes >= 0 && $minutes < 60) $this->minutes = $minutes;
}public function setHours($hours)
{
if ($hours >= 0 && $hours < 24) $this->hours = $hours;
}}
We only want to perform checks on write, so instead of writing the trivial
getters, the property is set to the variable itself. Child classes could
reattach it to a function if needing more control.
Ouch. I messed up on the example code. Completely forget that there
was a parameter to process...
As for reading $seconds directly ...
Well.
If you think of the element that follows read as $this->xxxx, then if
the parser can handle both ...
read $seconds
read getSeconds
then yes for both.
If not, then I'd guess that the getSeconds version should be the one
we use as the value may not actually exist without some processing.
Richard.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Richard Quadling wrote:
As for reading $seconds directly ...
Well.
If you think of the element that follows read as $this->xxxx, then if
the parser can handle both ...read $seconds
read getSecondsthen yes for both.
If not, then I'd guess that the getSeconds version should be the one
we use as the value may not actually exist without some processing.Richard.
If it begins with $, it's a variable name, so map to that class member
variable. If it is instead a plain T_STRING, take that as a member call.
I'm not sure to be understanding the issue you're mentioning.
2010/11/29 Ángel González keisial@gmail.com:
Richard Quadling wrote:
As for reading $seconds directly ...
Well.
If you think of the element that follows read as $this->xxxx, then if
the parser can handle both ...read $seconds
read getSecondsthen yes for both.
If not, then I'd guess that the getSeconds version should be the one
we use as the value may not actually exist without some processing.Richard.
If it begins with $, it's a variable name, so map to that class member
variable. If it is instead a plain T_STRING, take that as a member call.I'm not sure to be understanding the issue you're mentioning.
If the proposal incorporated support for getting the value from a
local-scoped variable (I assume the variable has to be part of the
current class or one of its parents?) as well as calling the getter,
then that really does seem to allow everyone everything they need.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Richard Quadling wrote:
(I assume the variable has to be part of the current class or one of its parents?)
Yes. I don't think it makes sense to have a class property actually read
a global.
If a project really need it (eg. some migration from procedural style to
classes), then
use the verbose syntax.
Hi !
This is my first email here (I'm just a PHP user, with only very basic C skills, but I'm working on it), and I would love to contribute to this project.
I have been working with Objective-c lately, and it has a very flexible and short way to deal with properties, which could look like this in PHP :
<?php
class TimePeriod {
protected $seconds;
protected $minutes;
protected $hours;
@synthesize (readwrite) $hours, $minutes;
@synthesize (readonly) $seconds;
}
NB : I intentionally skipped the @property declaration wich I believe is a specific need for objc (used to allow dot syntax usage).
In objc, this notation allows to :
- use dot syntax for accessing properties (using their getters/setters only, all properties are protected in objc)
- write your own getters/setters (only the missing ones are generated)
In Php, the pros of this syntax would be :
- very concise
- no interference with existing code (except certain conditions)
- allows to override generated getters and setters with custom code
- may work with the existing code base
The cons :
- new syntax to learn (even if it is quite simple)
- need to use pre-determined setters and getters names to keep simplicity, which could potentially lead to BC break in some (hopefully rare) cases.
What do you think about it ?
Regards,
Benjamin
Le 29 nov. 2010 à 17:10, Richard Quadling a écrit :
2010/11/29 Ángel González keisial@gmail.com:
Richard Quadling wrote:
setMilliseconds() should have $value as parameter instead of a magic name.What about allowing this syntax to attach the property to a variable?
For instance:
<?php
class TimePeriod
{
protected $seconds;
protected $minutes;
protected $hours;public property Seconds read $seconds write setSeconds;
public property Minutes read $seconds write setMinutes;
public property Hours read $seconds write setHours;public function setSeconds($seconds)
{
if ($seconds >= 0 && $seconds < 60) $this->seconds = $seconds;
}public function setMinutes($minutes)
{
if ($minutes >= 0 && $minutes < 60) $this->minutes = $minutes;
}public function setHours($hours)
{
if ($hours >= 0 && $hours < 24) $this->hours = $hours;
}}
We only want to perform checks on write, so instead of writing the trivial
getters, the property is set to the variable itself. Child classes could
reattach it to a function if needing more control.Ouch. I messed up on the example code. Completely forget that there
was a parameter to process...As for reading $seconds directly ...
Well.
If you think of the element that follows read as $this->xxxx, then if
the parser can handle both ...read $seconds
read getSecondsthen yes for both.
If not, then I'd guess that the getSeconds version should be the one
we use as the value may not actually exist without some processing.Richard.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
What about allowing this syntax to attach the property to a variable?
For instance:
<?php
class TimePeriod
{
protected $seconds;
protected $minutes;
protected $hours;public property Seconds read $seconds write setSeconds; public property Minutes read $seconds write setMinutes; public property Hours read $seconds write setHours; public function setSeconds($seconds) { if ($seconds>= 0&& $seconds< 60) $this->seconds = $seconds; } public function setMinutes($minutes) { if ($minutes>= 0&& $minutes< 60) $this->minutes = $minutes; } public function setHours($hours) { if ($hours>= 0&& $hours< 24) $this->hours = $hours; }
}
We only want to perform checks on write, so instead of writing the trivial
getters, the property is set to the variable itself. Child classes could
reattach it to a function if needing more control.
Another advantage here would presumably be performance. If there's no
getter defined then the engine could simply map $foo->bar to the class
member directly (which is really fast) and not to a method, so there's
no added overhead there. That still leaves the question of what happens
with name collisions, though.
... and that makes me think that someone is sure to ask about runtime
changes to the property structure sooner or later, as we keep asking
about methods (and sort of have figured out with binding closures to
objects, if that did actually get committed), so I'll go ahead and ask
it now. :-)
--Larry Garfield
Another advantage here would presumably be performance. If there's
no
getter defined then the engine could simply map $foo->bar to the
class
member directly (which is really fast) and not to a method, so
there's
no added overhead there. That still leaves the question of what
happens
with name collisions, though.
Don't kow what you mean by "the engine" in this case? The compiler? - no
the compiler can't a) it has no idea what type $foo is b) think about
inheritance etc. The executor - well there's no win possible.
johannes
Another advantage here would presumably be performance. If there's
no
getter defined then the engine could simply map $foo->bar to the
class
member directly (which is really fast) and not to a method, so
there's
no added overhead there. That still leaves the question of what
happens
with name collisions, though.Don't kow what you mean by "the engine" in this case? The compiler? - no
the compiler can't a) it has no idea what type $foo is b) think about
inheritance etc. The executor - well there's no win possible.johannes
I was referring to the compiler I guess. I don't do C so I have no idea
what it's capable of. If that's not a possible performance optimization
point, then blargh.
I still want to keep the performance implications in mind, as this
sounds like something that we'd want to use a lot but could also cost a
lot more than it seems at first glance if we're not careful.
--Larry Garfield
I still want to keep the performance implications in mind, as this
sounds like something that we'd want to use a lot but could also cost a
lot more than it seems at first glance if we're not careful.
By making properties in memory a little bigger one might write the
accessors in the same table as the actual properties one might possibly
reduce the CPU requirement abit. While one has to touch most places
dealing with properties internally (while that's probably needed
anyways). But well, unless there is an implementation all performance
ideas are guesses ... educated guesses at best.
johannes
<snip>Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntaxThanks,
Dennis RobinsonI'd really like this feature to be part of PHP.
I don't particularly like the use of what looks like a closure for the set/get.
I used to code in Delphi and I always like the way in which their
properties were defined.Essentially, the setter and getter are normal methods which are cherry
picked for a property [1].<?php
class TimePeriod
{
protected $seconds;public property Hours read getHours write setHours; protected function getHours() { return $this->seconds / 3600; } protected function setHours() { $this->seconds = $value * 3600; }
For me, the advantage here is that I can independently the methods
from the property. If I want to force a subclass to implement a
setter/getter, then I can abstract the function in the base class.
I prefer this as well. It often aids readability to use fluent
interfaces when performing operations that are simply changing state,
and being able to call the setters directly would make that possible:
$time->setHours(3)
->setMinutes(17)
->setSeconds(34);
Additionally, this seems like a very natural fit with traits, making it
possible to really succinctly define behavior to mix in with classes.
--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Hi!
public property Hours read getHours write setHours;
I actually like that, though I think we should support the whole
existing semantics, i.e. get/set/isset/unset. And probably keep the
names, so we don't call the same thing both "read" and "get".
Having them called __get etc. would even remove the need for another
keyword, probably, but this looks ugly :(
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi Richard,
I'd really like this feature to be part of PHP.
I don't particularly like the use of what looks like a closure for the
set/get.
While it looks like a closure, it may not necessarily be one. What I have
presented in my RFC is a syntax, but I make little assumption about how it
would be implemented, as that would be out stepping my expertise.
In C#, when a property gets compiled it is actually turned into two normal
class methods in a special namespace. Looking at a compiled C# library
with reflector will reveal this underlying implementation. So when a call
to a property is compiled in C#, it is simple replaced with a call to a
method. The properties themselves are nothing more than syntactic sugar.
Since PHP is interpreted instead of compiled, this may not be an ideal
solution, but I couldn't guess as to what would be a better method.
Preferably something that re-uses the existing class method
interpretation.
I used to code in Delphi and I always like the way in which their
properties were defined.Essentially, the setter and getter are normal methods which are cherry
picked for a property [1].<?php
class TimePeriod
{
protected $seconds;public property Hours read getHours write setHours; protected function getHours() { return $this->seconds / 3600; } protected function setHours() { $this->seconds = $value * 3600; } // This property is read-only public property Minutes read getMinutes; protected function getMinutes() { return $this->seconds / 60; } public property Milliseconds read getMilliseconds write
setMilliseconds;
public function getMilliseconds() { // This method is public return $this->seconds * 60; } protected function setMilliseconds() { // This method is protected $this->seconds = $value * 3600; }
}
For me, the advantage here is that I can independently the methods
from the property. If I want to force a subclass to implement a
setter/getter, then I can abstract the function in the base class.
Sure, some may say that I should be using an interface. I disagree as
I probably don't want the methods to be public. Protected or even
private and/or final.
In the syntax I provided in my RFC, it is certainly possible to define a
property with only a get or only a set method (these are implicit
read-only and write-only properties). Furthermore, it is also possible to
set the visibility of the get and set methods individually, as well as
making either one final, static or (and I forgot to mention this in the
RFC) abstract. But the advantage of my syntax, is not only can these
things be set individually, but they can also be set just once for the
pair, by specifying them on the property itself. This makes for cleaner
and more readable code.
My syntax also gives several other advantages over the delphi syntax. It
is more logical, as it makes the property look more like a class variable
than a class method. This makes sense because you call it like a
variable. Additionally, because the get/set methods need to be contained
within the body of the property definition, you immediately know if a
property has both a get and a set method at a quick glance - you do not
have to hunt through the class to see if there is another definition
somewhere else.
The classic example is one of shapes. Every shape has a public $area
property, but the value would be provided by an abstract protected
TShape::getArea(); method. I can also finalise them, so, for example,
a triangle shape could have a final protected getArea() method and all
sub classes of triangles (scalene, isosceles, equilateral) would not
implement their own getArea() method.
This is possible with the syntax I provided. I would suggest reading more
about the C# syntax, which my suggested syntax is based off of, as it will
explain all of your questions.
http://msdn.microsoft.com/en-us/library/x9fsa0sw%28VS.80%29.aspx
- Dennis
Hi Richard,
I'd really like this feature to be part of PHP.
I don't particularly like the use of what looks like a closure for the
set/get.While it looks like a closure, it may not necessarily be one. What I have
presented in my RFC is a syntax, but I make little assumption about how it
would be implemented, as that would be out stepping my expertise.In C#, when a property gets compiled it is actually turned into two normal
class methods in a special namespace. Looking at a compiled C# library
with reflector will reveal this underlying implementation. So when a call
to a property is compiled in C#, it is simple replaced with a call to a
method. The properties themselves are nothing more than syntactic sugar.Since PHP is interpreted instead of compiled, this may not be an ideal
solution, but I couldn't guess as to what would be a better method.
Preferably something that re-uses the existing class method
interpretation.I used to code in Delphi and I always like the way in which their
properties were defined.Essentially, the setter and getter are normal methods which are cherry
picked for a property [1].<?php
class TimePeriod
{
protected $seconds;public property Hours read getHours write setHours;
protected function getHours()
{
return $this->seconds / 3600;
}protected function setHours()
{
$this->seconds = $value * 3600;
}// This property is read-only
public property Minutes read getMinutes;protected function getMinutes()
{
return $this->seconds / 60;
}public property Milliseconds read getMilliseconds write
setMilliseconds;public function getMilliseconds()
{
// This method is public
return $this->seconds * 60;
}protected function setMilliseconds()
{
// This method is protected
$this->seconds = $value * 3600;
}
}For me, the advantage here is that I can independently the methods
from the property. If I want to force a subclass to implement a
setter/getter, then I can abstract the function in the base class.
Sure, some may say that I should be using an interface. I disagree as
I probably don't want the methods to be public. Protected or even
private and/or final.In the syntax I provided in my RFC, it is certainly possible to define a
property with only a get or only a set method (these are implicit
read-only and write-only properties). Furthermore, it is also possible to
set the visibility of the get and set methods individually, as well as
making either one final, static or (and I forgot to mention this in the
RFC) abstract. But the advantage of my syntax, is not only can these
things be set individually, but they can also be set just once for the
pair, by specifying them on the property itself. This makes for cleaner
and more readable code.My syntax also gives several other advantages over the delphi syntax. It
is more logical, as it makes the property look more like a class variable
than a class method. This makes sense because you call it like a
variable. Additionally, because the get/set methods need to be contained
within the body of the property definition, you immediately know if a
property has both a get and a set method at a quick glance - you do not
have to hunt through the class to see if there is another definition
somewhere else.The classic example is one of shapes. Every shape has a public $area
property, but the value would be provided by an abstract protected
TShape::getArea(); method. I can also finalise them, so, for example,
a triangle shape could have a final protected getArea() method and all
sub classes of triangles (scalene, isosceles, equilateral) would not
implement their own getArea() method.This is possible with the syntax I provided. I would suggest reading more
about the C# syntax, which my suggested syntax is based off of, as it will
explain all of your questions.http://msdn.microsoft.com/en-us/library/x9fsa0sw%28VS.80%29.aspx
- Dennis
Thanks for your reply.
Fundamentally, a big +1 from my little voice on having setters/getters in PHP.
The issue of documentation is probably that the documentation tools
would have to adapt. As things stand PHPDoc doesn't support
namespaces, so setters/getters would just be added to the WIBNI list.
With regard to the value supplied to the set method, would it make
more sense for PHP to be ...
set($value) { $this->seconds = $value * 3600; }
or
set { $this->seconds = __SETVALUE__ * 3600; }
Having $value without a clear indication of where it comes from
doesn't read quite right.
$value is way to generic to be magically created. SETVALUE (or
SOMETHINGELSE) is clear in this regard.
Richard.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Thanks for your reply.
Fundamentally, a big +1 from my little voice on having setters/getters in
PHP.The issue of documentation is probably that the documentation tools
would have to adapt. As things stand PHPDoc doesn't support
namespaces, so setters/getters would just be added to the WIBNI list.
Here is a reply I wrote to Christan Kaps on the same subject:
Christan Wrote:
I like the idea of the property get/set syntax, but in my opinion it
doesn't figure with PHP's syntax, because it breaks the readability. The
problem for me is the nesting of the inner set and get. How do you
document these syntax./**
*/
public $name {/** * */ get { return $this->name; } /** * */ set { $this->name = htmlentities($value); $this->name = strip_tags($this->name); }
};
Typically you only document the property as a whole, and not the
individual get and set method. Since they are a pair, there should be no
reason to document them separately. If the get method is doing something
totally different from the set, then they should not be paired, as that is
confusing.
In C# you would typically see documentation like this:
Only a get method:
/// <summary>Gets the duration of the Timespan in seconds.</summary>
public int Seconds { get; }
Only a set method:
/// <summary>Sets the duration of the Timespan in seconds.</summary>
public int Seconds { set; }
Both a get and set method:
/// <summary>Gets/sets the duration of the Timespan in seconds.</summary>
public int Seconds { get; set; }
With regard to the value supplied to the set method, would it make
more sense for PHP to be ...set($value) { $this->seconds = $value * 3600; }
or
set { $this->seconds = __SETVALUE__ * 3600; }
Having $value without a clear indication of where it comes from
doesn't read quite right.$value is way to generic to be magically created. SETVALUE (or
SOMETHINGELSE) is clear in this regard.
That is a good point. In C# it is simple the variable "value", which is
where I got $value from. Rather magicy, yes. A constant could work, and
would be more in line with PHP's magic constants. Just a quick question
though, can a constant store all of the same data variable can? What
about a reference?
Also, sometimes users in C# like to modify the contents of the "value"
variable before using it for something else. If it were a constant this
would not be possible, you would have to define a new variable, then copy
the value from the constant, which seems unnecessarily cumbersome.
- Dennis
Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntax
Nice RFC, just an idea for an alternative syntax (added to the RFC as #2):
property Hours {
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; } // The variable $value holds
the incoming value to be "set"
}
class TimePeriod
{
private $seconds;
public [Hours] $hours1;
public {use Hours;} $hours2;
}
Would favor re-use similar to traits by injecting the set/get code around
the property.
Hi!
Nice RFC, just an idea for an alternative syntax (added to the RFC as #2):
property Hours {
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; } // The variable $value holds
the incoming value to be "set"
}class TimePeriod
{
private $seconds;public [Hours] $hours1; public {use Hours;} $hours2;
}
If you change "property" to "class" or "trait" and "get" to "__get" you
need almost no new syntax :)
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Nice RFC, just an idea for an alternative syntax (added to the RFC as #2):
property Hours {
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; } // The variable $value holds
the incoming value to be "set"
}class TimePeriod
{
private $seconds;public [Hours] $hours1; public {use Hours;} $hours2;
}
If you change "property" to "class" or "trait" and "get" to "__get" you
need almost no new syntax :)
Not really. With __get() and __set(), it's entirely likely that the class into
which the trait is mixed in might override this already -- and not take into
account the properties. That would be quite a brittle solution.
--
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
Hi!
Nice RFC, just an idea for an alternative syntax (added to the RFC
as
#2):property Hours {
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; } // The variable $value
holds
the incoming value to be "set"
}class TimePeriod
{
private $seconds;public [Hours] $hours1; public {use Hours;} $hours2;
}
If you change "property" to "class" or "trait" and "get" to "__get"
you need almost no new syntax :)
Right, it looks the same but the subtle difference is 'property Hours'
wouldn't be registered as a class. It's just container code for get(), set()
methods that would get 'compiled' into opcodes in the class TimePeriod (the
property exists vs. searching for it in runtime). So you can think of it as
a special 'trait' that only applies to properties.
The idea behind this syntax is you can move the 'property' definition out of
the class so that you can test and re-use it somewhere else (like traits).
That might not be problem if you can define properties in traits (needs to
be explained in the RFC):
trait TimeUnits {
public property Seconds
{
get { return $this->seconds; }
set { $this->seconds = $value; }// The variable $value holds the
incoming value to be "set"
}
public property Minutes
{
get { return $this->seconds / 60; }
set { $this->seconds = $value * 60; }
}
public property Hours
{
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; }// The variable $value holds
the incoming value to be "set"
}
}
class MyTime {
uses TimeUnits;
protected $_seconds;
}
Right, it looks the same but the subtle difference is 'property Hours'
wouldn't be registered as a class. It's just container code for get(), set()
methods that would get 'compiled' into opcodes in the class TimePeriod (the
property exists vs. searching for it in runtime). So you can think of it as
a special 'trait' that only applies to properties.The idea behind this syntax is you can move the 'property' definition out of
the class so that you can test and re-use it somewhere else (like traits).That might not be problem if you can define properties in traits (needs to
be explained in the RFC):
I think I'd prefer to use Traits for externally-defined properties
rather than defining a new top-level construct. It's fewer moving parts
and we don't need to figure out how autoloading would be affected.
(Autoload would work the same way it does now for traits... whatever
that is.)
That would then imply we do need to be able to declare the existence of
a property and whether it has get, set, or both independently of the
definition, just like methods, so that we can have a proper
interface/trait split for properties just as for methods.
--Larry Garfield
Hello,
Hi!
Nice RFC, just an idea for an alternative syntax (added to the RFC
as
#2):property Hours {
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; } // The variable $value
holds
the incoming value to be "set"
}class TimePeriod
{
private $seconds;public [Hours] $hours1; public {use Hours;} $hours2;
}
If you change "property" to "class" or "trait" and "get" to "__get"
you need almost no new syntax :)Right, it looks the same but the subtle difference is 'property Hours'
wouldn't be registered as a class. It's just container code for get(),
set()
methods that would get 'compiled' into opcodes in the class TimePeriod
(the
property exists vs. searching for it in runtime). So you can think of it
as
a special 'trait' that only applies to properties.The idea behind this syntax is you can move the 'property' definition out
of
the class so that you can test and re-use it somewhere else (like traits).That might not be problem if you can define properties in traits (needs to
be explained in the RFC):
trait TimeUnits {
public property Seconds
{
get { return $this->seconds; }
set { $this->seconds = $value; }// The variable $value holds the
incoming value to be "set"
}
public property Minutes
{
get { return $this->seconds / 60; }
set { $this->seconds = $value * 60; }
}
public property Hours
{
get { return $this->seconds / 3600; }
set { $this->seconds = $value * 3600; }// The variable $value
holds
the incoming value to be "set"
}
}class MyTime {
uses TimeUnits;protected $_seconds;
}
I do not think that properties should make use of a trait-like syntax, as
that is not what a property is about. A property is basically a layer of
syntactic sugar over a pair of methods. The majority of the time when
writing properties, you will not want to re-use them, so I have a hard
time seeing many parallels to traits.
However, it does make sense to be able to define a property as part of a
trait, as again, it is basically just a pair of methods. When I get some
time, I will try to add a syntax for traits to the RFC.
- Dennis
Hi:
However, it does make sense to be able to define a property as part of a
trait, as again, it is basically just a pair of methods. When I get some
time, I will try to add a syntax for traits to the RFC.
The only thing really necessary for that would be a specification on how to name/to refer to the getter/setter to be able to handle the conflicts.
The rest should work out of the box. As far as I can see from the proposal.
Best regards
Stefna
- Dennis
--
--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax: +32 2 629 3525
Hi!
I do not think that properties should make use of a trait-like syntax, as
that is not what a property is about. A property is basically a layer of
syntactic sugar over a pair of methods. The majority of the time when
writing properties, you will not want to re-use them, so I have a hard
time seeing many parallels to traits.
A side note: in PHP, property actually has four methods, not two -
get/set/unset/isset.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hello Stas,
I do not think that properties should make use of a trait-like syntax,
as
that is not what a property is about. A property is basically a layer
of
syntactic sugar over a pair of methods. The majority of the time when
writing properties, you will not want to re-use them, so I have a hard
time seeing many parallels to traits.A side note: in PHP, property actually has four methods, not two -
get/set/unset/isset.
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.
Because properties (as defined in my RFC) are not a variable, but rather a
set of methods, I do not think there would be any way to "unset" them.
Like a method, once they are defined, you cannot get rid of them.
Therefore "overloading" isset and unset would not make any sense here.
- Dennis
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.Because properties (as defined in my RFC) are not a variable, but rather a
set of methods, I do not think there would be any way to "unset" them.
Like a method, once they are defined, you cannot get rid of them.
Therefore "overloading" isset and unset would not make any sense here.
This is different from the PHP Language then. You can isset() and
unset() "native" properties. And use __isset() and __unset() magic
methods.
A new feature should be consistent with the language definition.
johannes
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.Because properties (as defined in my RFC) are not a variable, but rather
a
set of methods, I do not think there would be any way to "unset" them.
Like a method, once they are defined, you cannot get rid of them.
Therefore "overloading" isset and unset would not make any sense here.This is different from the PHP Language then. You can isset() and
unset() "native" properties. And use __isset() and __unset() magic
methods.A new feature should be consistent with the language definition.
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.
isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.
__isset() is a whole different matter, without it we would have to assume
that every possible member name either exists or does not exist. This is
because __isset can handle ANY member name.
Properties are bound to a single member name, therefore, they always
exist, unless you were to physically remove that property from the class,
which, like methods, that is not possible.
- Dennis
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.Because properties (as defined in my RFC) are not a variable, but rather
a
set of methods, I do not think there would be any way to "unset" them.
Like a method, once they are defined, you cannot get rid of them.
Therefore "overloading" isset and unset would not make any sense here.This is different from the PHP Language then. You can isset() and
unset() "native" properties. And use __isset() and __unset() magic
methods.A new feature should be consistent with the language definition.
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.
Consistency with other languages must also be balanced against
consistency within PHP. Both are important.
Class members and both existing class-member-ish mechanisms (__magic and
ArrayAccess) have the concept of isset/unset. A third class-member-ish
(syntactically speaking) mechanism will be expected to have the same set
of primitives. To not have them will be a major language WTF, because
to a normal user of an object they look like class members, not
methods, they taste like class members, not methods, so they should
act like class members, not methods.
Basically, properties can only be considered a drop-in replacement for
class members (as you've stated, correctly, is one of the potential big
wins for them) if they fully emulate their behavior. If they do not,
then it is incorrect to say that they can be swapped in for a class
member without changing an API.
__isset() is a whole different matter, without it we would have to assume
that every possible member name either exists or does not exist. This is
because __isset can handle ANY member name.Properties are bound to a single member name, therefore, they always
exist, unless you were to physically remove that property from the class,
which, like methods, that is not possible.
No, but it can be easily emulated.
Actually, I can even think of a concrete use case. Suppose I have an
object that acts as a facade for a remote object over SOAP, REST, or
whatever. It is using properties to represent attributes of a remote,
say, insurance account. I want to know if a beneficiary has been set on
the account. The most straightforward way to do so is
if (isset($account->beneficiary)) {
print $account->beneficiary->name;
}
If we are implementing such logic via __get(), we can do exactly that.
If we are implementing it via properties, we should still be able to.
Forcing the user to know that he needs to do it this way instead, but
only if we're using properties rather than __get():
if ($account->hasBeneficiary()) {
print $account->beneficiary->name;
}
is violating the principle of encapsulation as it means the user needs
to know which of the three forms of $account->beneficiary happens to be
in use.
Thinking about properties further, actually, there's two other (related)
considerations that always give me grief when dealing with __get:
Reference returns and complex member variables.
If I want a reference to a class member, I can very easily do this:
$foo = &$bar->baz;
If ->baz is accessed via __get(), then that only works if __get() is
defined as function &__get($var) to start with. That's another
encapsulation break.
Similarly, the following does exactly what you'd expect with a normal
class member:
$foo->bar['baz']->narf = 'poink';
If $foo->bar is returned via __get(), though, then the above statement
executes but does not actually save anything... unless __get() was
defined to return by reference as above.
Details of my adventures in __get() insanity here, including performance
considerations:
http://www.garfieldtech.com/blog/magical-php-call
How would properties deal with those scenarios? (The answer may well be
"it doesn't, screw off, that's way too esoteric", as it is for __get(),
but we should at least consider if it's possible to handle those
gracefully.)
--Larry Garfield
Hi!
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.
This is also true for object properties - see magic methods. I don't see
why you shouldn't be able to unset them - you can do that with regular
properties... So what you imagine would happen if you call
unset($foo->property) or isset($foo->property)?
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.This is also true for object properties - see magic methods. I don't see
why you shouldn't be able to unset them - you can do that with regular
properties... So what you imagine would happen if you call
unset($foo->property) or isset($foo->property)?
As I replied elsewhere:
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.
isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.
__isset is a whole different matter, without it we would have to assume
that every possible member name in a class either exists or does not
exist. This is because __isset, __get, __set and __unset can handle ANY
member name.
Properties are bound to a single member name, therefore, they always
exist, unless you were to physically remove that property from the class,
which, like methods, that is not possible.
- Dennis
Object properties (or members, classic ->var, not this proposed syntax) CURRENTLY, work this way:
php -r 'class foo { public $bar; } $foo = new foo(); var_dump(isset($foo->bar));'
bool(false)
This is because you are confusing PHP's isset() with a property_exists()
. Is set. Is the variable (or member/property)
set to a value?
In this case, both isset() and unset() work with the property get/set you are proposing. Imagine:
$results = $db->query('SELECT SQL_CALC_FOUND_ROWS * FROM some_table WHERE foo = 'bar');
if (isset($results->count)) {
foreach ($results->getResult() as $result) {
// Do something
}
}
where isset() would hit:
protected property count {
isset {
$result = $this->execute('SELECT FOUND_ROWS()');
$this->count = $result->getColumn();
if ($this->count == 0) {
return false;
}
return false;
}
}
Not an ideal example, but it gives you an IDEA off the top of my head of a way to take advantage of it
- Davey
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.This is also true for object properties - see magic methods. I don't see
why you shouldn't be able to unset them - you can do that with regular
properties... So what you imagine would happen if you call
unset($foo->property) or isset($foo->property)?As I replied elsewhere:
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.__isset is a whole different matter, without it we would have to assume
that every possible member name in a class either exists or does not
exist. This is because __isset, __get, __set and __unset can handle ANY
member name.Properties are bound to a single member name, therefore, they always
exist, unless you were to physically remove that property from the class,
which, like methods, that is not possible.
- Dennis
Hi Davey,
Object properties (or members, classic ->var, not this proposed syntax)
CURRENTLY, work this way:php -r 'class foo { public $bar; } $foo = new foo();
var_dump(isset($foo->bar));'
bool(false)This is because you are confusing PHP's isset() with a
property_exists()
.
Is set. Is the variable (or member/property)
set to a value?
I did not know of property_exists()
, very interesting!
In this case, both isset() and unset() work with the property get/set you
are proposing. Imagine:$results = $db->query('SELECT SQL_CALC_FOUND_ROWS * FROM some_table WHERE
foo = 'bar');if (isset($results->count)) {
foreach ($results->getResult() as $result) {
// Do something
}
}where isset() would hit:
protected property count {
isset {
$result = $this->execute('SELECT FOUND_ROWS()');
$this->count = $result->getColumn();
if ($this->count == 0) {
return false;
}
return false;
}
}Not an ideal example, but it gives you an IDEA off the top of my head of a
way to take advantage of it
Well, I understand the concept and how it would work, but I just don't
think its logical. In my mind, being able to make a property appear to
disappear makes as much sense as making a class method appear to
disappear. This is absolutely no good for inheritance for one thing.
The __isset method makes perfect sense, because all variables handled with
__get and __set don't truly exist. They are not actually defined in the
class, they are just "fake" class members, whose data comes from somewhere
else - maybe an array. So __isset is there to say which "fake" member
names do and don't exist.
But when defined, a property, like a method, shouldn't be able to just
"disappear". It is a specific definition and should never appear to be
missing. If you need a class member that can be unset, you should be
using __isset __get and __set, because that is exactly what those are
meant for.
My feelings are that a property "foo" should behave exactly like a
getFoo() and setFoo($value) pair of methods. You can always call these
methods, and never worry that you will get a "method not set" error. When
you call getFoo() you are always guaranteed to get something, even if it
is simply NULL.
Maybe I am missing your point? But it does not make logical sense to me,
the way you suggest.
Also, would adding isset not make properties much slower? Calling
$object->foo would first have to call and process the "isset" method to
determine if it is set, then after getting "true" from isset, it would be
able to call "get". And what happens if there is no "isset"? Is it just
always guaranteed to be set then?
- Dennis
Hi:
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.This is also true for object properties - see magic methods. I don't see
why you shouldn't be able to unset them - you can do that with regular
properties... So what you imagine would happen if you call
unset($foo->property) or isset($foo->property)?Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way.
I tend to disagree.
The need to be consistent inside of PHP has precedence over being consistent with other languages.
You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.
I think, it really is the other way around.
Properties are meant to give the programmer the illusion that she is just having a field.
That is abstraction. She does not care about implementation details.
And that is the power of properties.
isset() and unset() are perfectly fine in that context.
And I do not see a problem to provide the standard semantics for them automatically, and let the programmer add isset/unset methods to the property as needed in exactly the same style as get/set.
There is a good usecase for asking whether a property has been set, for instance to verify initialization.
And, of course unset has also a useful meaning. It is about the value, and even so there are methods around a value, properties are meant to be values.
There are definitely use-cases where that does not hold, but that is application specific.
isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.
From the docu: isset — Determine if a variable is set and is notNULL
There is nothing confusing about isset($this->Hours) ==FALSE
in your example if isset($this->seconds) == FALSE.
Best regards
Stefan
--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax: +32 2 629 3525
That is true for PHP variables. isset is basically saying "does this
variable exist", and unset is saying to get rid of it.This is also true for object properties - see magic methods. I don't
see
why you shouldn't be able to unset them - you can do that with regular
properties... So what you imagine would happen if you call
unset($foo->property) or isset($foo->property)?Its not a matter of consistency - Properties, as a cross-language
concept
are not meant to work that way.
I tend to disagree.
The need to be consistent inside of PHP has precedence over being
consistent with other languages.
Unfortunately I find that to be one of the major downfalls of PHP. It
sometimes disregards defacto standards that are set across the entire
industry, which causes a lot of frustration for new programmers.
Sometimes the functionality PHP adds by going its own way is worth it, but
often it is just a confusing mess. Thats just my opinion though, YMMV.
You need to think of a property as a set
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.
I think, it really is the other way around.
Properties are meant to give the programmer the illusion that she is just
having a field.
That is abstraction. She does not care about implementation details.
And that is the power of properties.isset() and unset() are perfectly fine in that context.
And I do not see a problem to provide the standard semantics for them
automatically, and let the programmer add isset/unset methods to the
property as needed in exactly the same style as get/set.There is a good usecase for asking whether a property has been set, for
instance to verify initialization.
And, of course unset has also a useful meaning. It is about the value, and
even so there are methods around a value, properties are meant to be
values.
There are definitely use-cases where that does not hold, but that is
application specific.isset() in the way you suggest would just be confusing. It would allow
is
to say that a property does not exist, when in fact it does exist. This
is not logical.
From the docu: isset Determine if a variable is set and is notNULL
There is nothing confusing about isset($this->Hours) ==FALSE
in your
example if isset($this->seconds) == FALSE.
Right, I understand how it would work, and the reasons why it would "make
sense", but it just feels wrong to me. When you unset() a variable in a
class, that whole variable is gone. Its not just hiding somewhere, its
completely gone. If a property were to "pretend" it is not set, with an
isset method, it would still be there - just hiding. That is why it does
not make sense to me.
- Dennis
Unfortunately I find that to be one of the major downfalls of PHP. It
sometimes disregards defacto standards that are set across the entire
industry, which causes a lot of frustration for new programmers.
Sometimes the functionality PHP adds by going its own way is worth it, but
often it is just a confusing mess. Thats just my opinion though, YMMV.
Still, if it is not consistent in itself it is worse than not following certain designs which make sense for other languages only.
isset() in the way you suggest would just be confusing. It would allow
is
to say that a property does not exist, when in fact it does exist. This
is not logical.
From the docu: isset — Determine if a variable is set and is notNULL
There is nothing confusing about isset($this->Hours) ==FALSE
in your
example if isset($this->seconds) == FALSE.Right, I understand how it would work, and the reasons why it would "make
sense", but it just feels wrong to me. When you unset() a variable in a
class, that whole variable is gone. Its not just hiding somewhere, its
completely gone. If a property were to "pretend" it is not set, with an
isset method, it would still be there - just hiding. That is why it does
not make sense to me.
The main problem here is that unset and isset are not symmetric.
isset() basically means there is a value.
Where unset() destroys the holder of the value.
In that sense, unset is special since it works on another level, on the same level as property_exists()
.
There are several possible approaches, but the main point here is that at least isset() still makes sense.
property_exists()
and unset() should be dealt with carefully in another way.
Best regards
Stefan
--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax: +32 2 629 3525
Hi Stefan,
Unfortunately I find that to be one of the major downfalls of PHP. It
sometimes disregards defacto standards that are set across the entire
industry, which causes a lot of frustration for new programmers.
Sometimes the functionality PHP adds by going its own way is worth it,
but
often it is just a confusing mess. Thats just my opinion though, YMMV.Still, if it is not consistent in itself it is worse than not following
certain designs which make sense for other languages only.
Yes, I would agree with that.
isset() in the way you suggest would just be confusing. It would
allow is
to say that a property does not exist, when in fact it does exist.
This is not logical.
From the docu: isset Determine if a variable is set and is notNULL
There is nothing confusing about isset($this->Hours) ==FALSE
in your
example if isset($this->seconds) == FALSE.Right, I understand how it would work, and the reasons why it would "make
sense", but it just feels wrong to me. When you unset() a variable in a
class, that whole variable is gone. Its not just hiding somewhere, its
completely gone. If a property were to "pretend" it is not set, with an
isset method, it would still be there - just hiding. That is why it
does not make sense to me.The main problem here is that unset and isset are not symmetric.
isset() basically means there is a value.
Where unset() destroys the holder of the value.In that sense, unset is special since it works on another level, on the
same level asproperty_exists()
.There are several possible approaches, but the main point here is that at
least isset() still makes sense.
property_exists()
and unset() should be dealt with carefully in another
way.
Ok. Well isset() could just run the get handler for the property, and if
it is null, return false, and otherwise return true.
- Dennis
isset() in the way you suggest would just be confusing. It would
allow is
to say that a property does not exist, when in fact it does exist.
This
is not logical.
Even when a property does exist physically (by these "methods") it might
not exist logically.
Missing that functionality is inconsistent with the languages. such an
inconsistency would be enough reason for a -1000 vote :-)
johannes
Hi!
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a set
Meant by whom? Is there some law of universe that prevents us from
implementing the feature?
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.
If you need methods, why not use methods? If you mimick object
properties, however, it makes sense to make them work exactly like
property, otherwise you have to explain why they don't work this way.
isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.
Sorry, from your answer I don't understand - what happens when you call
isset($foo->property) and unset($foo->property)?
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
Its not a matter of consistency - Properties, as a cross-language concept
are not meant to work that way. You need to think of a property as a setMeant by whom? Is there some law of universe that prevents us from
implementing the feature?of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.If you need methods, why not use methods? If you mimick object properties,
however, it makes sense to make them work exactly like property, otherwise
you have to explain why they don't work this way.isset() in the way you suggest would just be confusing. It would allow is
to say that a property does not exist, when in fact it does exist. This
is not logical.Sorry, from your answer I don't understand - what happens when you call
isset($foo->property) and unset($foo->property)?
If we think of properties as this new entity for the language (rather
than somehow massaging existing entities to fit a new usage scenario),
then
isset($instance->property) will always return true for any defined
property. Even if the getter would return null. This is new behaviour
and can be easily documented. isset() for a property is more like
method_exists()
than isset() on a variable.
With regard to unset($instance->property), from the manual ...
"The behavior of unset() inside of a function can vary depending on
what type of variable you are attempting to destroy."
So, we already have differing behaviour based upon context. Attempting
to destroy a property should through a non fatal error.
One idea I had was to keep just the get/set property methods and add
to them an additional parameter ...
<?php
public $seconds {
public set($value, $unset = False) {
if ($unset) {
// unset() has been called on the property.
// In this instance $value will be Null.
} else {
// set the property using the supplied $value.
}
},
public get($isset = False) {
if ($isset) {
// isset() has been called on the property.
// If the value is a non-destructive calculation then maybe
returning the comparison of the result of the calculation to null.
} else {
// return the value for this property.
}
}
};
So,
isset($instance->property) would call $instance->property->get(True);
unset($instance->property) would call $instance->property->set(Null, True);
This keeps just the 2 property methods. It still allows isset/unset
and allows the developer the option of handling them.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Hi!
If we think of properties as this new entity for the language (rather
than somehow massaging existing entities to fit a new usage scenario),
then
I think the idea of new entity of the language looking exactly like old
entity of the language but having different rules is kind of non-starter.
One idea I had was to keep just the get/set property methods and add
to them an additional parameter ...
So we have one set of properties where get and isset use different
methods and another set of properties where get and isset use same
method but with parameter. I think it's not the best way to go. It's
better to ignore isset altogether than this.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
So we have one set of properties where get and isset use different methods
and another set of properties where get and isset use same method but with
parameter. I think it's not the best way to go. It's better to ignore isset
altogether than this.
No. The prototype of all setters would be the same. As would the
prototype of all getters.
The prototype would be ...
[public|protected|private] property $property {
[public|protected|private] mixed|bool get([bool $isset = false]) {
// mixed result for get, bool result for isset
},
[public|protected|private] mixed|void set(mixed $value [, bool
$unset = false]) { // mixed result for set, void result for unset
},
};
From a user's perspective ...
echo isset($instance->property) ? 'isset to ' . $instance->property :
'not isset';
This would result in 2 calls ...
property->get(true) // Let the getter that an attempt is being made to
see if the property has been set.
and
property->get(false) // Let the getter know that the getter is
expected to return the properties value.
Similarly for the setter.
$instance->property = 'foo';
unset($instance->property);
would result in 2 calls ...
property->set('foo', false) // Let the setter know that it should be
setting the value of the property to 'foo'.
and
property->set(null, true) // Let the setter know that an attempt to
unset the property has taken place.
Maybe the proposal should be changed to ...
[public|protected|private] property $property {
[public|protected|private] mixed get() {
},
[public|protected|private] mixed set(mixed $value) {
},
[public|protected|private] bool isset() {
},
[public|protected|private] void unset() {
},
};
(NOTE: Add in abstract and final as appropriate).
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
Hi!
No. The prototype of all setters would be the same. As would the
prototype of all getters.
But we'd have two sets of properties - one handled by __get/__isset,
another - by get($isset). Not a good idea.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
No. The prototype of all setters would be the same. As would the
prototype of all getters.But we'd have two sets of properties - one handled by __get/__isset, another
- by get($isset). Not a good idea.
So, should properties isset/unset go via the magic methods?
With properties, there would be the duplication anyway (__get()/get()
and __set()/set()).
Either way, only the property knows what should happen when an isset()
or unset() is called against it. It is for that reason that I think
the property should handle it.
__get, __set, __isset and __unset are for undefined class members. Not
properties. From the user of the class, completely invisible.
Having more than 1 way to skin the cat is pretty much de rigueur for PHP.
--
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY
So we have one set of properties where get and isset use different
methods
and another set of properties where get and isset use same method but
with
parameter. I think it's not the best way to go. It's better to ignore
isset
altogether than this.No. The prototype of all setters would be the same. As would the
prototype of all getters.The prototype would be ...
[public|protected|private] property $property {
[public|protected|private] mixed|bool get([bool $isset = false]) {
// mixed result for get, bool result for isset
},
[public|protected|private] mixed|void set(mixed $value [, bool
$unset = false]) { // mixed result for set, void result for unset
},
};From a user's perspective ...
echo isset($instance->property) ? 'isset to ' . $instance->property :
'not isset';This would result in 2 calls ...
property->get(true) // Let the getter that an attempt is being made to
see if the property has been set.
and
property->get(false) // Let the getter know that the getter is
expected to return the properties value.Similarly for the setter.
$instance->property = 'foo';
unset($instance->property);would result in 2 calls ...
property->set('foo', false) // Let the setter know that it should be
setting the value of the property to 'foo'.
and
property->set(null, true) // Let the setter know that an attempt to
unset the property has taken place.Maybe the proposal should be changed to ...
[public|protected|private] property $property {
[public|protected|private] mixed get() {
},
[public|protected|private] mixed set(mixed $value) {
},
[public|protected|private] bool isset() {
},
[public|protected|private] void unset() {
},
};(NOTE: Add in abstract and final as appropriate).
This last syntax makes far more sense than adding parameters to the
get/set methods. The problem however, is what does isset and unset
do/return if they are not defined? What if I only want to define the
get/set and I do not define the isset/unset? If they are required,
properties are far too complex to be useful. But if they are optional, we
are back to the same problem of what isset() and unset() are supposed to
do...
- Dennis
Hi Richard:
If we think of properties as this new entity for the language (rather
than somehow massaging existing entities to fit a new usage scenario),
thenisset($instance->property) will always return true for any defined
property. Even if the getter would return null. This is new behaviour
and can be easily documented. isset() for a property is more like
method_exists()
than isset() on a variable.
I tend to see that rather different.
Properties are not about methods, properties as in C# are about abstracting from the actual realization of how the state is represented internally that is exposed by a property.
Thus, properties like proposed here should be used to provide the illusion of having normal class variables. And in that scenario it makes sense to talk about the value the property represents and not the fact that there are methods.
So, from my point of view isset/unset have perfectly valid semantics on many of the usual cases.
Even so, I agree, there are cases where that is not so, but in those cases isset/unset could be specialize like set/get.
Best regards
Stefan
--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax: +32 2 629 3525
Its not a matter of consistency - Properties, as a cross-language
concept
are not meant to work that way. You need to think of a property as a
setMeant by whom? Is there some law of universe that prevents us from
implementing the feature?
Its a defacto standard. Of course there is nothing stopping PHP from
implementing properties that way, but by going against the standard set by
the rest of the industry, it is very confusing for programmers coming from
other languages to learn PHP. A good example is how "==" works
differently in PHP than in other languages. In PHP, "===" works like "=="
does everywhere else. "(string)'0' == (int)0", for example is true in
PHP, but false in most other languages. I have had countless
conversations with PHP developers who claim the language is "broken",
because == does not work like they expect it to, after which I have to
explain === to them. This is because PHP goes against the defacto
standard. Maybe it would have been better if == and === had the opposite
meaning, as to not squash the standard?
of two methods that just have a pretty syntax. Methods cannot be unset,
and nor should properties be allowed to. isset() should simply tell us
whether a property with the specified name is part of the class or not.If you need methods, why not use methods?
Because properties are only meant to be a pretty syntax for a get/set
method. Thats it! I don't know of any other special behaviour in any
other language that lets you "hide" properties or anything else like that.
isset() in the way you suggest would just be confusing. It would allow
is
to say that a property does not exist, when in fact it does exist. This
is not logical.Sorry, from your answer I don't understand - what happens when you call
isset($foo->property) and unset($foo->property)?
You make a good point. If we can't unset a property, than we lose
consistency with regular variables which I guess ruins the point of
properties.
- Dennis
Hi!
the rest of the industry, it is very confusing for programmers coming from
other languages to learn PHP. A good example is how "==" works
differently in PHP than in other languages. In PHP, "===" works like "=="
does everywhere else. "(string)'0' == (int)0", for example is true in
Not everywhere. Perl has the same rules, for example.
explain === to them. This is because PHP goes against the defacto
standard. Maybe it would have been better if == and === had the opposite
meaning, as to not squash the standard?
There's no such standard. PHP works differently than the language you
knew before, that's it. If it worked the same, it would be the same
language.
Because properties are only meant to be a pretty syntax for a get/set
method. Thats it! I don't know of any other special behaviour in any
other language that lets you "hide" properties or anything else like that.
If that's it, we probably don't need them. They would just hide what
happens in the code and confuse the user, which would not know what
$a->foo means - would it work according to class attribute rules or
class method rules?
I think, however, this syntax might be useful - for example, Zend
Framework does a lot of property/method linking, some other frameworks
do that too, and individual methods might be better than catch-all in
this case. But that requires consistency.
In PHP, of course, class properties are dynamic, so you can add and
delete them at will. It is a standard feature of dynamic languages. For
a person coming from strict compiled language like C# it might be
unusual, but that's how dynamic languages work.
You make a good point. If we can't unset a property, than we lose
consistency with regular variables which I guess ruins the point of
properties.
It doesn't have to - if we can find a consistent concept of how to do
it. But we need to think about it.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hello Stas,
In PHP, of course, class properties are dynamic, so you can add and
delete them at will. It is a standard feature of dynamic languages. For
a person coming from strict compiled language like C# it might be
unusual, but that's how dynamic languages work.
No not unusual at all. You can dynamically add properties to class
instances in C# as well. My point was that methods cannot dynamically be
added or removed from class instances, even though variables can.
I think what it comes down to, is it wont be possible to remove the actual
property definition from the instance, but just be able to hide it, or
make it appear like it is missing, to be consistent with the behaviour of
standard variables.
This makes for another issue though. If I unset() the property $foo, and
then (because its gone), attempt to set $foo to something else, this is
going to activate the property definitions set method, when I only
expected a variable to be created. This is because the property
definition still exists, but is just hiding (returning false from its
isset handler). How should this situation be handled?
- Dennis
president@basnetworks.net wrote:
Its a defacto standard. Of course there is nothing stopping PHP from
implementing properties that way, but by going against the standard set by
the rest of the industry, it is very confusing for programmers coming from
other languages to learn PHP. A good example is how "==" works
differently in PHP than in other languages. In PHP, "===" works like "=="
does everywhere else. "(string)'0' == (int)0", for example is true in
PHP, but false in most other languages. I have had countless
conversations with PHP developers who claim the language is "broken",
because == does not work like they expect it to, after which I have to
explain === to them. This is because PHP goes against the defacto
standard. Maybe it would have been better if == and === had the opposite
meaning, as to not squash the standard?
You have got me there.
= is assign
== is equal value
=== is equal type and value
At least on all the languages I've been using recently ... where is this a problem?
Also isset() makes perfect sense when you have NULL
values coming from a
database. unset then kicks a NULL
back to the database if updating. The varable
exists but has a NULL
value ...
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk//
Firebird - http://www.firebirdsql.org/index.php
Hi Derick,
Link to the RFC:
http://wiki.php.net/rfc/propertygetsetsyntax-1
Derick
Care to elaborate? I'm not sure much consideration will be taken of your
opinion unless you put some words behind it. I am curious to know why you
did not like the RFC?
Regards,
- Dennis