I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.
Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php works,
only how their own code works. If they define an accessor they expect to
see an accessor, reflection should reflect that there are accessors and
no other "methods" they did not explicitly define. If they were to
reflect on all of the methods of their class and see a number of
__getHours() they may be confused as to why or where this function came
from. From their perspective, they have defined an accessor and "how"
that accessor works on the inside is of no importance to them and only
seeks to complicate or confuse matters when they are exposed to these
"implementation details" of the php language its-self. If you tried to
set a value such as $obj?abc = 1 through an accessor which could not be
set, you would probably want to see an error like: Warning, cannot set
Class?abc, no setter defined.
Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic, then
you want to see them, you want to call them directly if you so choose.
In effect you want nothing hidden from you. In this case you probably
don't even want Reflection to reflect accessors as anything different
than specially formatted and called methods on the class. This can be
understandable because you want all information available to you. You
would probably not be confused if you wrote $obj?abc = 1 and got back an
error like "Fatal Error: Class->__setAbc() function does not exist.
Unfortunately 80 to 95% of all people who use PHP are of the first type.*
Revealing these internal matters to them would only leave them confused,
possibly frustrated and likely asking about it to the internals mailing
list to answer (repeatedly).
Thoughts?
--
-Clint
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php works,
only how their own code works. If they define an accessor they expect to
see an accessor, reflection should reflect that there are accessors and
no other "methods" they did not explicitly define. If they were to
reflect on all of the methods of their class and see a number of
__getHours() they may be confused as to why or where this function came
from. From their perspective, they have defined an accessor and "how"
that accessor works on the inside is of no importance to them and only
seeks to complicate or confuse matters when they are exposed to these
"implementation details" of the php language its-self. If you tried to
set a value such as $obj?abc = 1 through an accessor which could not be
set, you would probably want to see an error like: Warning, cannot set
Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic, then
you want to see them, you want to call them directly if you so choose.
In effect you want nothing hidden from you. In this case you probably
don't even want Reflection to reflect accessors as anything different
than specially formatted and called methods on the class. This can be
understandable because you want all information available to you. You
would probably not be confused if you wrote $obj?abc = 1 and got back an
error like "Fatal Error: Class->__setAbc() function does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first type.*
Revealing these internal matters to them would only leave them confused,
possibly frustrated and likely asking about it to the internals mailing
list to answer (repeatedly).Thoughts?
I personally don't think there's such a huge difference between the two
'groups'. When people in group 1 use reflection to examine their
accessors, they should have enough knowledge to understand how accessors
are implemented. If we document it well, I don't really see that as a
problem.
- Tul
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by an accessor
declaration should be invisible and non-callable directly. Others are in favor of leaving
them visible and callable.
If we leave them callable,
-
What would be the effects of users defining the "internal" methods (in both cases of
if/if not the accessor is also defined)? Considering current magic methods are
purposefully designed to be implemented by the user, I expect users to try this and, if
it works, release code with it. -
I assume one could use them as regular methods?
- call_user_func([$foo, '__getpropName']);
- $foo->{"__get$propName"}
I apologize if these were already covered.
Steve Clay
Hi!
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.
I think these types are not right. It has nothing to do with
internals/userland, it has to do with wanting more magic that work is a
complex way while allowing user no knowledge and control over what's
going on, or reduced number of simple concepts that interact in a
variety of ways. You can say it's Windows model vs. Unix model, if you
need monikers.
Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php works,
only how their own code works. If they define an accessor they expect to
see an accessor, reflection should reflect that there are accessors and
Again, this insists on the notion that there's such accepted thing as
"accessor" in PHP field, which already has a known behavior and set of
expectations, and these match exactly the proposal of "invisible". But
this is not true at all - only successors existing so far in PHP are
regular perfectly visible methods. So if you expect to see an accessor,
you expect to see __get. If you appeal to natural expectations of PHP
user, you can not argue it is "for accessors to be accessors", because
PHP has never had anything like you proposed, and there's no any
accepted definition of "accessor" that implies what you are implying.
no other "methods" they did not explicitly define. If they were to
reflect on all of the methods of their class and see a number of
__getHours() they may be confused as to why or where this function came
Please do not insult the intelligence of PHP users. They are not some
mindless creatures that given property Hours, previous existence of
__get and __getHours can not figure out what's going on, even after
being told of the new accessors feature (since they're using it in the
code). They won't be confused. Nobody knowing how to program a
hello-world would. This mythical easily-confusable users do not exist,
but if they did, they'd just not use reflection because it'd be too
confusing for them anyway.
than specially formatted and called methods on the class. This can be
understandable because you want all information available to you. You
This has very little to do with information available. This has
everything to do with
would probably not be confused if you wrote $obj?abc = 1 and got back an
error like "Fatal Error: Class->__setAbc() function does not exist.
You can very easily handle the error in the same handler that you look
for setter, this is not an issue at all. In general, error messages have
very little to do with the whole thing. If the error messages is the
thing you're worried about - it should be trivially easy to fix, since
all access will go through object handlers anyway, and the object
handler would decide to throw the error - so you'd be able very easily
to issue any error message you like.
Unfortunately 80 to 95% of all people who use PHP are of the first type.*
Not really. There are a lot of programmers that aren't Windows type, and
prefer simple interfaces to ones with a lot of complicated magic. --
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.I think these types are not right. It has nothing to do with
internals/userland, it has to do with wanting more magic that work is a
complex way while allowing user no knowledge and control over what's
going on, or reduced number of simple concepts that interact in a
variety of ways.
I think you are presenting the situation inaccurately. This has
nothing to do with complex magic and also does not intend to limit the
users control. Actually, both approaches are exactly the same, the
only difference is whether we additionally put the accessor function
into the method table or whether we do not.
I still fail to see where you see complexity come into the picture.
You have mentioned inheritance checking, but from what I see the
functions doing the inheritance check take generic zend_function*s, so
they wouldn't have a problem dealing with code not in the method
table. The same applies to pretty much everything else too. After all,
there is a reason why we have abstractions in the engine ;)
To me the situation is as simple as this: I declared a get accessor
for $foo. I did not declare the method __getfoo(). So why is that
method there?
It seems really pointless, counter-intuitive and hacky to me to
automatically create methods that do not actually exist (not under
that name at least).
Nikita
Hi!
users control. Actually, both approaches are exactly the same, the
only difference is whether we additionally put the accessor function
into the method table or whether we do not.
They may be almost the same technically, but very different
conceptually. Your approach means we introduce new complex concept of
not-quite-method, which can be called only in some special
circumstances, has special handling by compiler, backtraces, reflection,
tools, etc. and requires people to learn this new concept and be always
aware of it to be able to correctly operate it. My approach is that you
just have another magic method, which we already have plenty in PHP, and
does not require any new concepts introduced, and works very similar to
existing access magics.
I still fail to see where you see complexity come into the picture.
Described above. You want to introduce new entity into PHP called
"accessor", which looks like PHP method, but lives outside of the PHP
method table, is not callable by regular means (though might be callable
by special means, but you have no way to use methods' reflection to know
if such call would succeed or not) and requires special considerations.
This is more complex than using already existing concepts, by definition
- more concepts is more complex than less concepts.
You have mentioned inheritance checking, but from what I see the
functions doing the inheritance check take generic zend_function*s, so
they wouldn't have a problem dealing with code not in the method
table. The same applies to pretty much everything else too. After all,
there is a reason why we have abstractions in the engine ;)
They won't have a problem. They won't deal with these not-quite-methods.
That's exactly the problem - we already have mechanism of dealing with
inheritance, and you propose to introduce another one to deal with
additional complexity of methods not in method table.
To me the situation is as simple as this: I declared a get accessor
for $foo. I did not declare the method __getfoo(). So why is that
method there?
This in not simple. You know what "accessor" is. The other 100% of PHP
users have no idea what "accessor" is. They know what methods are, they
know what magics are. So if I tell them "we have extensions of __get
that allow you to do __getFoo" - they instantly know what's going on. If
I tell them "we have accessors" - they'd have to go and read the manual
to understand what is going on and which additional restriction you
placed on them in order to force them into your preconception of
"accessor".
It seems really pointless, counter-intuitive and hacky to me to
automatically create methods that do not actually exist (not under
that name at least).
What you mean by "do not actually exist"? Of course they exist, that's
the whole point. You will be running them, how they don't exist? You
just want hide their existence by introducing a bunch of complex checks
all over the engine under the premise that showing the user the real
methods in function table would "confuse" them. It won't. The only thing
it would do is contradict your idea that there's some definition of
"accessors" that requires them to not be methods. I see no reason for
such definition. It is an option, but having them as methods is an
option too, and in my opinion a much better one.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
users control. Actually, both approaches are exactly the same, the
only difference is whether we additionally put the accessor function
into the method table or whether we do not.They may be almost the same technically, but very different
conceptually. Your approach means we introduce new complex concept of
not-quite-method, which can be called only in some special
circumstances, has special handling by compiler, backtraces, reflection,
tools, etc. and requires people to learn this new concept and be always
aware of it to be able to correctly operate it. My approach is that you
just have another magic method, which we already have plenty in PHP, and
does not require any new concepts introduced, and works very similar to
existing access magics.I still fail to see where you see complexity come into the picture.
Described above. You want to introduce new entity into PHP called
"accessor", which looks like PHP method, but lives outside of the PHP
method table, is not callable by regular means (though might be callable
by special means, but you have no way to use methods' reflection to know
if such call would succeed or not) and requires special considerations.
This is more complex than using already existing concepts, by definition
- more concepts is more complex than less concepts.
You have mentioned inheritance checking, but from what I see the
functions doing the inheritance check take generic zend_function*s, so
they wouldn't have a problem dealing with code not in the method
table. The same applies to pretty much everything else too. After all,
there is a reason why we have abstractions in the engine ;)They won't have a problem. They won't deal with these not-quite-methods.
That's exactly the problem - we already have mechanism of dealing with
inheritance, and you propose to introduce another one to deal with
additional complexity of methods not in method table.To me the situation is as simple as this: I declared a get accessor
for $foo. I did not declare the method __getfoo(). So why is that
method there?This in not simple. You know what "accessor" is. The other 100% of PHP
users have no idea what "accessor" is. They know what methods are, they
know what magics are. So if I tell them "we have extensions of __get
that allow you to do __getFoo" - they instantly know what's going on. If
I tell them "we have accessors" - they'd have to go and read the manual
to understand what is going on and which additional restriction you
placed on them in order to force them into your preconception of
"accessor".It seems really pointless, counter-intuitive and hacky to me to
automatically create methods that do not actually exist (not under
that name at least).What you mean by "do not actually exist"? Of course they exist, that's
the whole point. You will be running them, how they don't exist? You
just want hide their existence by introducing a bunch of complex checks
all over the engine under the premise that showing the user the real
methods in function table would "confuse" them. It won't. The only thing
it would do is contradict your idea that there's some definition of
"accessors" that requires them to not be methods. I see no reason for
such definition. It is an option, but having them as methods is an
option too, and in my opinion a much better one.
Stas, if you define an accessor, how do you define it? Do you say
public $foo {
get() { ... }
set($value) { ... }
}
or do you say
public function __getFoo() { ... }
public function __setFoo($value) { ... }
?
According to the current proposal at least you can write the first
code and the first code only. If you write the second code then you
define two methods __getFoo and __setFoo and nothing more. Those
methods will not be called when you write $bar->foo. If just defining
the methods would cause $bar->foo to be intercepted, then __getFoo
etc would indeed be just magic methods with "dynamic" names. But as
already said, this is not the case, so you would have
magic-methods-which-aren't-really-magic-methods (extra for you, as you
like the term not-quite-method so much ^^).
You keep saying that the term "accessors" would be somehow a lot
harder to understand for users and that telling them something about
__getFoo and __setFoo will be easier to grasp. I don't know about you,
but I think that if you want to explain this new shiny feature to a
user you would start off with a code like public $foo { get() { ... }
... } and explain that that those are accessors and are used to define
special behavior for properties. You probably won't start off with
telling them that this declaration is automatically converted to a set
of __getFoo methods which are registered as handlers for the accessor.
I really don't see how going into details like __getFoo makes anything
easier.
:)
Nikita
Hi!
Stas, if you define an accessor, how do you define it? Do you say
Either way, doesn't matter.
According to the current proposal at least you can write the first
code and the first code only. If you write the second code then you
That's where I think it is wrong. It would be much simpler and
consistent with existing PHP if it were a natural extension of __get
instead of a completely new and foreign concept.
special behavior for properties. You probably won't start off with
telling them that this declaration is automatically converted to a set
of __getFoo methods which are registered as handlers for the accessor.
I really don't see how going into details like __getFoo makes anything
easier.
Depending on your purpose and background. If you know how __get works,
extrapolating to __getFoo is trivial. Getting special syntax that
produces __getFoo from this is also trivial.
Getting the concept of methods that are not quite methods and get called
only through special intercept mechanism and have special backtrace
rewriting engine and reflection hiding patches so you can be inside the
method that officially does not exist - not so trivial.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
Stas, if you define an accessor, how do you define it? Do you say
Either way, doesn't matter.According to the current proposal at least you can write the first
code and the first code only. If you write the second code then you
That's where I think it is wrong. It would be much simpler and
consistent with existing PHP if it were a natural extension of __get
instead of a completely new and foreign concept.special behavior for properties. You probably won't start off with
telling them that this declaration is automatically converted to a set
of __getFoo methods which are registered as handlers for the accessor.
I really don't see how going into details like __getFoo makes anything
easier.
Depending on your purpose and background. If you know how __get works,
extrapolating to __getFoo is trivial. Getting special syntax that
produces __getFoo from this is also trivial.Getting the concept of methods that are not quite methods and get called
only through special intercept mechanism and have special backtrace
rewriting engine and reflection hiding patches so you can be inside the
method that officially does not exist - not so trivial.
The only thing that does back patching is for static accessors and
you've already pointed out that what I was doing to make that happen is
just going to break and fail in so many ways.
What is "reflection hiding patches" referring to? Reflection is changed
to reflect what the user has defined, that's what reflection is supposed
to be.. no?
Lastly, this idea that accessors is such a foreign concept is a bit
ridiculous. You'd be hard pressed to find a modern/popular language
these days that doesn't have them, so if someone is confused about what
an accessor is then they probably have their head in the sand, god
forbid they'd have to read the manual.
--
-Clint
Hi!
What is "reflection hiding patches" referring to? Reflection is changed
to reflect what the user has defined, that's what reflection is supposed
to be.. no?
No. Reflection is supposed to show which methods exist on a class, which
can be called from certain context, etc. This has nothing to do with
where they were defined.
Lastly, this idea that accessors is such a foreign concept is a bit
ridiculous. You'd be hard pressed to find a modern/popular language
these days that doesn't have them, so if someone is confused about what
PHP doesn't have them. Also, by your definition, Python doesn't have
them - in Python, __ methods are regular methods. Also, by your
definition, Ruby doesn't have them either - in Ruby, you define them as
regular methods, and you very well can call them too:
http://stackoverflow.com/questions/621176/how-to-dynamically-call-accessor-methods-in-ruby#621193.
Javascript doesn't have them either. Java doesn't have them either. So
I'm not that hard pressed to find languages that don't follow your
model, as you can see.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas, you should probably do some research before posting such non-sense:
http://en.wikipedia.org/wiki/Property_%28programming%29
Every language you mentioned has them. Perhaps the confusion is that I
am calling them accessors since other languages refer to accessors as
"properties" while PHP refers to "properties" the way that other
languages refer to them as "fields" or "data members."
By accessors I am simply referring to getters, setters (and in the case
of php, issetter and unsetter).
Hi!
What is "reflection hiding patches" referring to? Reflection is changed
to reflect what the user has defined, that's what reflection is supposed
to be.. no?
No. Reflection is supposed to show which methods exist on a class, which
can be called from certain context, etc. This has nothing to do with
where they were defined.Lastly, this idea that accessors is such a foreign concept is a bit
ridiculous. You'd be hard pressed to find a modern/popular language
these days that doesn't have them, so if someone is confused about what
PHP doesn't have them. Also, by your definition, Python doesn't have
them - in Python, __ methods are regular methods. Also, by your
definition, Ruby doesn't have them either - in Ruby, you define them as
regular methods, and you very well can call them too:
http://stackoverflow.com/questions/621176/how-to-dynamically-call-accessor-methods-in-ruby#621193.
Javascript doesn't have them either. Java doesn't have them either. So
I'm not that hard pressed to find languages that don't follow your
model, as you can see.
--
-Clint
Hi!
Stas, you should probably do some research before posting such non-sense:
Which part is "non-sense"? I've brought you examples of Python and Ruby
not doing exactly what you claim all languages are doing. By your
definition, they don't have accessors - as you define accessors as
hidden methods that are uncallable and unavailable and not defined as
regular methods. In both Ruby and Python they are callable and defined
as regular (or regular with some special attributes) method.
I've brought you examples of popular languages that don't have this
feature at all - Java and standard C++ don't have it. I was wrong on
Javascript - though in Javascript, functions work differently from PHP
so there's no real relation to the current discussion.
By accessors I am simply referring to getters, setters (and in the case
of php, issetter and unsetter).
I wish it was so, but it was mentioned many times in this discussion
that "accessors should be accessors" and that only the situation where
accessors are special functions that are not defined as regular methods,
are not callable and are hidden from reflection, etc. is the situation
where "accessors are accessors". This is not the case in Python, Ruby,
MS C++, D and Delphi by your own link - in all these cases, the
properties are defined as regular methods (possibly with some special
salt added) and no special effort is taken to hide them from any of the
language facilities and make them not callable.
Of course, there are also examples of languages going the other way -
namely, C#, F# and VB - but by no means the claim that I would be hard
pressed to find example of the languages which do not implement your
notion of "accessors being accessors" is true. For most dynamic
languages, the concept of "accessors being accessors" - hidden,
non-callable pseudo-methods - is a foreign concept.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas Malyshev wrote:
By accessors I am simply referring to getters, setters (and in the case
of php, issetter and unsetter).
I wish it was so, but it was mentioned many times in this discussion
that "accessors should be accessors" and that only the situation where
accessors are special functions that are not defined as regular methods,
are not callable and are hidden from reflection, etc. is the situation
where "accessors are accessors". This is not the case in Python, Ruby,
MS C++, D and Delphi by your own link - in all these cases, the
properties are defined as regular methods (possibly with some special
salt added) and no special effort is taken to hide them from any of the
language facilities and make them not callable.
While I will probably be shouted down again ... can we clarify WHAT people are
trying to achieve here?
__get and __set simply provide a crude means of using '$data' array to store
properties in an object without having to define and load them every time. It
has very limited use and in my own opinion is simply wrong anyway. But people
seem to like to use it rather than simply defining their own $data array and
accessing it directly? The reason it does not work for me is that I populate the
data array ( in my case $mInfo ) directly from the persistent data in a
database, and __get and __set simply do not work with this so never get used.
I can SEE the logic behind a get and set arrangement being 'formalised', and
mirroring __get and __set is obviously necessary, but part of the reason for
this discussion was - I thought - a way of allowing get/set to manage access to
internal data that may not be a simple mirror, but rather calculated from other
internal data ( hours based on second count )? 'Internal Accessor Method
Visibility' needs to provide the user with information on how a returned value
was generated? Even if that is only via documentation? Debugging that the
process is working is the thing that gets difficult if you can 'see' the process.
The discussion has been 'split up', but I see 'Extra shorthand declaration' as
another hiding of visibility such that 'public DateTime $date;' completely
bypasses setting up the DateTime object and that $date will have it's own
'accessors' or rather methods for accessing and configuring the object and it's
values!
PHP has something no other language has - 'very flexible arrays' - and we can
manage and pass data very nicely using these properly. Pass by reference allows
complex data to be passed and massaged in a way that 'accessors' simply can't
provide, and it's this method of working that we should be promoting rather than
trying to hide things 'because the user does not need to know about them'.
Everything used to be nicely visible in PHP, but that is becoming less the case
and getting back to a framework where the IDE can provide all of the 'eye-candy'
that is not needed when simply running the scripts should be considered as well?
--
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
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Hi!
Stas, you should probably do some research before posting such non-sense:
Which part is "non-sense"? I've brought you examples of Python and Ruby
not doing exactly what you claim all languages are doing. By your
definition, they don't have accessors - as you define accessors as
hidden methods that are uncallable and unavailable and not defined as
regular methods. In both Ruby and Python they are callable and defined
as regular (or regular with some special attributes) method.I've brought you examples of popular languages that don't have this
feature at all - Java and standard C++ don't have it. I was wrong on
Javascript - though in Javascript, functions work differently from PHP
so there's no real relation to the current discussion.By accessors I am simply referring to getters, setters (and in the case
of php, issetter and unsetter).
I wish it was so, but it was mentioned many times in this discussion
that "accessors should be accessors" and that only the situation where
accessors are special functions that are not defined as regular methods,
are not callable and are hidden from reflection, etc. is the situation
where "accessors are accessors". This is not the case in Python, Ruby,
MS C++, D and Delphi by your own link - in all these cases, the
properties are defined as regular methods (possibly with some special
salt added) and no special effort is taken to hide them from any of the
language facilities and make them not callable.
Of course, there are also examples of languages going the other way -
namely, C#, F# and VB - but by no means the claim that I would be hard
pressed to find example of the languages which do not implement your
notion of "accessors being accessors" is true. For most dynamic
languages, the concept of "accessors being accessors" - hidden,
non-callable pseudo-methods - is a foreign concept.
I see what you're talking about, I felt like you were saying these other
languages did not support accessors (getters, setters, etc). Those other
languages do not "hide" them, no. This was Nikita's suggestion, I will
let her fight for it.
-Clint
Hi!
Stas, you should probably do some research before posting such non-sense:
Which part is "non-sense"? I've brought you examples of Python and Ruby
not doing exactly what you claim all languages are doing. By your
definition, they don't have accessors - as you define accessors as
hidden methods that are uncallable and unavailable and not defined as
regular methods. In both Ruby and Python they are callable and defined
as regular (or regular with some special attributes) method.I've brought you examples of popular languages that don't have this
feature at all - Java and standard C++ don't have it. I was wrong on
Javascript - though in Javascript, functions work differently from PHP
so there's no real relation to the current discussion.By accessors I am simply referring to getters, setters (and in the case
of php, issetter and unsetter).I wish it was so, but it was mentioned many times in this discussion
that "accessors should be accessors" and that only the situation where
accessors are special functions that are not defined as regular methods,
are not callable and are hidden from reflection, etc. is the situation
where "accessors are accessors". This is not the case in Python, Ruby,
MS C++, D and Delphi by your own link - in all these cases, the
properties are defined as regular methods (possibly with some special
salt added) and no special effort is taken to hide them from any of the
language facilities and make them not callable.
Of course, there are also examples of languages going the other way -
namely, C#, F# and VB - but by no means the claim that I would be hard
pressed to find example of the languages which do not implement your
notion of "accessors being accessors" is true. For most dynamic
languages, the concept of "accessors being accessors" - hidden,
non-callable pseudo-methods - is a foreign concept.I see what you're talking about, I felt like you were saying these other
languages did not support accessors (getters, setters, etc). Those other
languages do not "hide" them, no. This was Nikita's suggestion, I will let
her fight for it.
If I got it right now, what Stas wants is that we introduce __getFoo
and __setFoo methods that will be called whenever an undefined ->foo
property is accessed and that the "normal" property accessors syntax
is made nothing more than a fancy notation for this.
I'm okay with one of those, but I highly advise against combining
both, i.e. either __getFoo and __setFoo OR a special accessor syntax.
The reason is that both carry different and non-combinable semantics.
A few examples:
A) Inheritance:
class A {
public $foo;
}
class B extends A {
public $foo { get() { ... } set($value) { ... } }
}
=> With the accessors syntax there is an expectation that the accessor
declaration will override the previous plain property. At least that's
what I would expect and that's what the code looks like
class A {
public $foo;
}
class B extends A {
public function __getFoo() { ... }
public function __setFoo($value) { ... }
}
=> With the magic syntax there is the expectation that the $foo
property will not be overridden. Rather the magic functions are
expected to do nothing, because the property already exists.
B) Interfaces:
interface A {
public $foo;
}
class B implements A {
public $foo { get() { ... } set($value) { ... } }
}
=> Here the accessor is expected to satisfy the interface
interface A {
public $foo;
}
class B implements A {
public function __getFoo() { ... }
public function __setFoo($value) { ... }
}
=> Here the magic methods don't satisfy the interface. Actually with
the magic methods approach the whole notion of properties or accessors
in interfaces becomes obsolete.
C) API semantics
The main advantage that accessors offer to me is that custom property
behavior can be a proper part of the public API. The magic __getFoo
/ __setFoo methods do not offer this. They are just another two magic
methods. On the other hand, proper accessors really define a
property with a certain behavior (the fact that they are bound to a
property is important here).
__getFoo and __setFoo are really not much of an improvement over
directly using __get and __set with a switch. It's just a small code
save. "Real" accessors on the other hand take properties to being a
first class API citizen.
D) Backing property
Additionally __getFoo / __setFoo would not allow us to access
$this->foo as the underlying "backing property". Whether or not this
approach has merits is a different discussion point, but the magic
method approach would make this impossible right from the start.
===
Point C) is most important to me (and directly related to A and B). I
really hope that we will implement proper accessors, rather than some
half-hearted implementation using magic methods.
Nikita
Hi!
If I got it right now, what Stas wants is that we introduce __getFoo
and __setFoo methods that will be called whenever an undefined ->foo
property is accessed and that the "normal" property accessors syntax
is made nothing more than a fancy notation for this.
Yes, pretty much, though "undefined" bit is not required I think. Not
100% convinced on this, but from user reqs it sounds like they want to
drop the undefined bit.
A) Inheritance:
class A { public $foo; } class B extends A { public $foo { get() { ... } set($value) { ... } } }
=> With the accessors syntax there is an expectation that the accessor
declaration will override the previous plain property. At least that's
what I would expect and that's what the code looks like
That's why I'm not liking the "undefined" bit.
=> With the magic syntax there is the expectation that the $foo
property will not be overridden. Rather the magic functions are
expected to do nothing, because the property already exists.
Err, I'm not sure why that would be the expectation. __get is for
undefined properties, since, well, it doesn't have any property name
attached, so it can't really be for defined properties :) However,
__getFoo (with whatever variations the bikeshedding committee will end
up with :) has property name attached to it, so requiring property be
undefined is not, well, required. Here we need to think which way is
better, and I currently tend to think accessor priority is better.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
If I got it right now, what Stas wants is that we introduce __getFoo
and __setFoo methods that will be called whenever an undefined ->foo
property is accessed and that the "normal" property accessors syntax
is made nothing more than a fancy notation for this.Yes, pretty much, though "undefined" bit is not required I think. Not
100% convinced on this, but from user reqs it sounds like they want to
drop the undefined bit.A) Inheritance:
class A { public $foo; } class B extends A { public $foo { get() { ... } set($value) { ... } } }
=> With the accessors syntax there is an expectation that the accessor
declaration will override the previous plain property. At least that's
what I would expect and that's what the code looks likeThat's why I'm not liking the "undefined" bit.
=> With the magic syntax there is the expectation that the $foo
property will not be overridden. Rather the magic functions are
expected to do nothing, because the property already exists.Err, I'm not sure why that would be the expectation. __get is for
undefined properties, since, well, it doesn't have any property name
attached, so it can't really be for defined properties :) However,
__getFoo (with whatever variations the bikeshedding committee will end
up with :) has property name attached to it, so requiring property be
undefined is not, well, required. Here we need to think which way is
better, and I currently tend to think accessor priority is better.
Stas, you seem to have missed the point behind my mail. This wasn't
about what the exact details of the implementation will be, the
message was that the semantics of a dedicated accessors syntax and the
semantics of a magic implementation can not match.
E.g. assuming that magic accessors take priority over properties as
you want it this time I can just turn the examples around:
class A {
public $foo { get() { ... } set($value) { ... } }
}
class B extends A {
public $foo;
}
=> Here I would expect that public $foo from class B overrides public
$foo from class A. With __ magic on the other hand:
class A {
public function __getFoo() { ... }
public function __setFoo($value) { ... }
}
class B extends A {
public $foo;
}
=> Here (according to your new overriding priority) the property in
class B would not override, rather the magic from A stays intact.
Basically any kind of interaction between properties and accessor
properties will be broken and inherently so, simply because magic
methods are not real properties (quite obviously...).
Nikita
Hi!
Stas, you seem to have missed the point behind my mail. This wasn't
about what the exact details of the implementation will be, the
message was that the semantics of a dedicated accessors syntax and the
semantics of a magic implementation can not match.
I see your point now, thanks, but I don't think I agree.
E.g. assuming that magic accessors take priority over properties as
you want it this time I can just turn the examples around:class A { public $foo { get() { ... } set($value) { ... } } } class B extends A { public $foo; }
=> Here I would expect that public $foo from class B overrides public
$foo from class A.
I'm not sure why you are expecting this, and also this is probably an
LSP violation, since such override would change semantics of the value
that A clients expect. It may be possible to implement, technically, but
I'm not sure it's the right thing to do.
Basically any kind of interaction between properties and accessor
properties will be broken and inherently so, simply because magic
methods are not real properties (quite obviously...).
Magic methods are not properties, they are implementation of properties.
But your properties aren't either - see discussion about interfaces,
etc. They simulate regular properties but they aren't regular
properties. E.g., what would happen if you serialize an object with
simulated property?
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi!
Stas, you seem to have missed the point behind my mail. This wasn't
about what the exact details of the implementation will be, the
message was that the semantics of a dedicated accessors syntax and the
semantics of a magic implementation can not match.I see your point now, thanks, but I don't think I agree.
E.g. assuming that magic accessors take priority over properties as
you want it this time I can just turn the examples around:class A { public $foo { get() { ... } set($value) { ... } } } class B extends A { public $foo; }
=> Here I would expect that public $foo from class B overrides public
$foo from class A.I'm not sure why you are expecting this, and also this is probably an
LSP violation, since such override would change semantics of the value
that A clients expect. It may be possible to implement, technically, but
I'm not sure it's the right thing to do.
Why would it be not expected and/or a violation of LSP? Accessors
impose stricly more restrictions than properties. This code is fine.
Just like it is fine in theory to have interface A { public $foo {
get(); set($v); } } class B implements A { public $foo; }
Basically any kind of interaction between properties and accessor
properties will be broken and inherently so, simply because magic
methods are not real properties (quite obviously...).Magic methods are not properties, they are implementation of properties.
But your properties aren't either - see discussion about interfaces,
etc. They simulate regular properties but they aren't regular
properties. E.g., what would happen if you serialize an object with
simulated property?--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227--
--
Etienne Kneuss
http://www.colder.ch
Hi!
I'm not sure why you are expecting this, and also this is probably an
LSP violation, since such override would change semantics of the value
that A clients expect. It may be possible to implement, technically, but
I'm not sure it's the right thing to do.Why would it be not expected and/or a violation of LSP? Accessors
impose stricly more restrictions than properties. This code is fine.
You assume accessors are restrictions, but they don't have to be. Consider:
public $foo { get() { return $this->foo;} set($v) { $this->foo_copy =
$this->foo = $v; } }
You have a postcondition on set() that $this->foo_copy will be the same
as $this->foo. Override with "public $foo" removes that postcondition.
But proper inheritance should only strengthen the postconditions, not
drop them.
Just like it is fine in theory to have interface A { public $foo {
get(); set($v); } } class B implements A { public $foo; }
That's different. In this case, you say "I will have some property
$foo", without promising anything about it. But specific code can
actually make some promises about $foo, and you can violate these
promises by overriding it with public $foo. Interface does not impose
any conditions except that $foo exist and is gettable/settable. Specific
getters/setters can impose much more involved conditions, which "public
$foo" may not be able to satisfy.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi,
Hi!
I'm not sure why you are expecting this, and also this is probably an
LSP violation, since such override would change semantics of the value
that A clients expect. It may be possible to implement, technically, but
I'm not sure it's the right thing to do.Why would it be not expected and/or a violation of LSP? Accessors
impose stricly more restrictions than properties. This code is fine.You assume accessors are restrictions, but they don't have to be. Consider:
public $foo { get() { return $this->foo;} set($v) { $this->foo_copy =
$this->foo = $v; } }You have a postcondition on set() that $this->foo_copy will be the same
as $this->foo. Override with "public $foo" removes that postcondition.
But proper inheritance should only strengthen the postconditions, not
drop them.
Well, LSP is typically not applied to program semantics, since this is
not a generally decidable problem. The only post-conditions that LSP
normally enforces is type based, i.e. the covariance of the return
type.
Instead, LSP simply states that, given B <: A, all objects of A can be
substituted by objects of B while preserving the validity of the
method calls on these objects, and the validity of their return
values. This is guaranteed here:
a get accessor will return a value of type any when performing
$a->foo, so does a property. LSP checks.
a set accessor takes a argument, so does $a->foo = "..". LSP checks.
My point is: all valid usages of accessors will also be valid when the
subclass overrides them using a normal property.
Just like it is fine in theory to have interface A { public $foo {
get(); set($v); } } class B implements A { public $foo; }That's different. In this case, you say "I will have some property
$foo", without promising anything about it. But specific code can
actually make some promises about $foo, and you can violate these
promises by overriding it with public $foo.
That's the same argument as before. Corresponding to LSP it only gives
very specific promises, that are simply type based and not the actual
strongest post-condition.
Interface does not impose
any conditions except that $foo exist and is gettable/settable. Specific
getters/setters can impose much more involved conditions, which "public
$foo" may not be able to satisfy.
Following your argument:
class A { public $v = 1; public foo() { $this->v = 2; } } class B
extends A {public foo() { $this->v = 4; }}
B should violate LSP, since the postcondition of B::foo() does not
imply postcondition of A::foo(). This is obviously not correct: this
code is fine.
Best,
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
--
Etienne Kneuss
http://www.colder.ch
Hi!
Well, LSP is typically not applied to program semantics, since this is
not a generally decidable problem. The only post-conditions that LSP
normally enforces is type based, i.e. the covariance of the return
type.
Err, I'm not sure where you are taking this from, but LSP is certainly
not limited to return types. See:
https://en.wikipedia.org/wiki/Liskov_substitution_principle
If you look at classic Square/Rectangle example, it's all about
semantics and has nothing to do with types.
Instead, LSP simply states that, given B <: A, all objects of A can be
substituted by objects of B while preserving the validity of the
method calls on these objects, and the validity of their return
values. This is guaranteed here:
I would suggest at that point reading actual description of the LSP. You
rendition of it is wrong.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi Stas, hi Etienne,
let’s get practical and apply LSP to property accessors. Find below what I would read from the characteristics of LSP.
Am 31.10.2012 um 20:46 schrieb Stas Malyshev smalyshev@sugarcrm.com:
[...]
Instead, LSP simply states that, given B <: A, all objects of A can be
substituted by objects of B while preserving the validity of the
method calls on these objects, and the validity of their return
values. This is guaranteed here:
Characteristics 1: Contravariance of method arguments in subtypes
This applies to properties in so forth, that weaker requirements need to be allowed. This means:
- Redeclaring a property without a specific type is OK (e.g. parent DateTime, children everything)
- Redeclaring a property with a supertype is OK (e.g. parent MyDateTime, children DateTime)
- Redeclaring a property that was read only as read-writable is OK in theory (it isn’t because of the history rule)
- Redeclaring a property with as less visible is not OK (parent public, children protected)
- Redeclaring a property with as more visible is OK (parent protected, children public)
- Redeclaring a property as read-only is not OK (parent rw, children ro)
Characteristics 2: Covariance of method return values in subtypes
- For properties, this basically mirrors the rules from rules from characteristics 1
Characteristics 3: Preconditions cannot be strengthened: This is something we cannot and should not prevent in the language itself but it’s up to the programmer to do this correctly
Characteristics 4: Postconditions cannot be weakened: See 3
Characterestics 5: History rule. See 3
cu,
Lars
Nikita, your examples convinced me that a strict "accessor methods as
specialized __get/__set semantics" approach is undesirable.
To recapitulate your two examples:
Example 1:
class A {
public $foo;
}
class B extends A {
public $foo { get() { ...} }
}
Example 2:
class A {
public $foo { get() { ...} }
}
class B extends A {
public $foo;
}
One would expect that in both cases, instances of 'class B' would have a $foo
acting as declared in class B, shadowing the declaration from class A.
I think that the issue might be solved by an additional, not-yet-discussed and
very general extension, which is something I missed being able to do from time
to time: the possibility to declare a method (or property) in some class to be
explicitly NOT inherited. Syntactically, something like
class C {
public $bar;
public function twiddle();
}
class D extends C {
no public $bar;
no public function twiddle();
might be followed by a different twiddle(), or $bar, implementation
}
The use case I have in mind, coming from the method side, is a subclass that
wants to use __call() for delegation AND needs to delegate to one or more
methods that are ordinarily plainly implemented in the base class.
What this feature would bring to the current discussion, is this possible
solution to your dilemma:
- when a class declares a plain property "public $foo", automatically apply
"no function __getfoo(); no function setfoo();" (leaving out isset/unset for
clarity) - conversely, when a class declares "public $foo { get() {...}}", or even
just declares one of the magic methods directly like "public function
__getfoo() {}" - automatically prepend / pretend a "no public $foo;"
cancelling a superclass property.
best regards
Patrick
I'm all for having the "internal" methods being totally normal magic
methods, for the reduced complexity reasons already mentioned.
I would also expect to be able to simply define such a magic method myself,
and have it behave in just the same way as when defining it using the
accessor declaration syntactic sugar.
To formulate it a different way: first expand on the current __get/__set
magic methods by clearly documenting a new set of per-property-name magic
methods, and the rules when they are called. Then on top of that, introduce
and document the accessor declaration syntactic sugar.
One point that came up some time ago, I'd like to mention again: there is
already a magic method named __set_state which would collide head on with
an accessor setter method for a property $_state IF that method would
follow the __set$PROPNAME pattern. As a solution for that, I'd propose
naming the new magic methods with a so-far-not-taken common prefix: __prop
- i.e. name them __prop_get_xxx, __prop_set_xxx, and so on.
best regards
Patrick
Hi!
an accessor setter method for a property $_state IF that method would
follow the __set$PROPNAME pattern. As a solution for that, I'd propose
naming the new magic methods with a so-far-not-taken common prefix: __prop
- i.e. name them __prop_get_xxx, __prop_set_xxx, and so on.
I think it'd more natural to make it __set__PROPNAME. Though __set_state
is a static method, so maybe we can live with it - except that you won't
be able to declare property named $_state.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
- i.e. name them __prop_get_xxx, __prop_set_xxx, and so on.
I think it'd more natural to make it __set__PROPNAME. Though __set_state
is a static method, so maybe we can live with it - except that you won't
be able to declare property named $_state.
Needing an "except" is inelegant, if it can be avoided up front.
Also, having __prop_get_XXX etc. is a bit more descriptive to somebody
later "wondering" what these methods are - prop alludes to properties,
which is what the methods are about. I can already see the stack overflow
subject, "what are these __prop methods in new PHP" :)
best regards
Patrick
That's why I think they shouldn't even be visible to users, they aren't
relevant to them and in fact it could mis-lead them into thinking that
they could simply define __getHours() and expect $foo->Hours to call
it, which it wouldn't.
To me, the bottom line is, the fact that there are methods defined by
accessors is an engine detail and not something that should be exposed
to the user.
As for the __set_state() issue, I can see the need to change the
pattern of method naming, I'd be amenable to anything.
Everyone okay with __get_prop_hours() naming convention then?
- i.e. name them __prop_get_xxx, __prop_set_xxx, and so on.
I think it'd more natural to make it __set__PROPNAME. Though __set_state
is a static method, so maybe we can live with it - except that you won't
be able to declare property named $_state.Needing an "except" is inelegant, if it can be avoided up front.
Also, having __prop_get_XXX etc. is a bit more descriptive to somebody
later "wondering" what these methods are - prop alludes to properties,
which is what the methods are about. I can already see the stack overflow
subject, "what are these __prop methods in new PHP" :)best regards
Patrick
--
-Clint
On Saturday 27 October 2012 13:05:27 Clint Priest wrote:
That's why I think they shouldn't even be visible to users, they aren't
relevant to them and in fact it could mis-lead them into thinking that
they could simply define __getHours() and expect $foo->Hours to call
it, which it wouldn't.
I would expect / want it to do so.
I see it this way:
Defining semantics for magic methods named __prop_get_XXX, __prop_set_XXX etc
as a specialization of __get/__set used whenever they exist for a given $XXX,
is in my eyes a complete, proper accessor enhancement, saving me from doing a
switch dance in __get/__set. The implementation should be absolutely
straightforward, in the place where a missing property now tests for existence
of __get/__set, a first, additional test for the specifically named
__prop_get_XXX method would be added.
Your proposed accessor syntax is purely syntactic sugar, implementable on
top of the functionality of the previous paragraph and implemented in terms of
automatic code generation for it. This syntactic sugar could be separately
implemented, discussed in a separate RFC,etc.
The added complexity that I see, and I think Stas has meant to mention a lot
of times, is everything - all code and documentation and explanation - that
stems from NOT making it that two-step process. And in my opinion that would
be completely superfluous, as it brings neither functionality nor syntax, just
random additional issues.
best regards
Patrick
Sounds like you're implying that the mere existence of a properly named
function such as __prop_get_hours() would cause it to be called instead
of returning the property.
There are several problems with this approach:
-
Currently __get() is only checked/invoked if there is not a property
already defined; ie properties shadow __get() (no performance penalty) -
It would dramatically reduce performance because every property
access would have to create the function string, get it's hash value and
do a hash look up against the function table, just to see if there is a
properly named accessor function. Failing that it would then check for
the existence of a property and failing that move on to looking up __get
-Clint
On Saturday 27 October 2012 13:05:27 Clint Priest wrote:
That's why I think they shouldn't even be visible to users, they aren't
relevant to them and in fact it could mis-lead them into thinking that
they could simply define __getHours() and expect $foo->Hours to call
it, which it wouldn't.
I would expect / want it to do so.I see it this way:
Defining semantics for magic methods named __prop_get_XXX, __prop_set_XXX etc
as a specialization of __get/__set used whenever they exist for a given $XXX,
is in my eyes a complete, proper accessor enhancement, saving me from doing a
switch dance in __get/__set. The implementation should be absolutely
straightforward, in the place where a missing property now tests for existence
of __get/__set, a first, additional test for the specifically named
__prop_get_XXX method would be added.Your proposed accessor syntax is purely syntactic sugar, implementable on
top of the functionality of the previous paragraph and implemented in terms of
automatic code generation for it. This syntactic sugar could be separately
implemented, discussed in a separate RFC,etc.The added complexity that I see, and I think Stas has meant to mention a lot
of times, is everything - all code and documentation and explanation - that
stems from NOT making it that two-step process. And in my opinion that would
be completely superfluous, as it brings neither functionality nor syntax, just
random additional issues.best regards
Patrick
--
-Clint
Hi!
- Currently __get() is only checked/invoked if there is not a property
already defined; ie properties shadow __get() (no performance penalty)
Yes, that's kind of the point of it - extending __get.
- It would dramatically reduce performance because every property
access would have to create the function string, get it's hash value and
do a hash look up against the function table, just to see if there is a
Not really, as we have property_info structure where we could record the
existence of such functions and we check property_info anyway AFAIR.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Am 28.10.2012 02:42 schrieb "Clint Priest" cpriest@zerocue.com:
Sounds like you're implying that the mere existence of a properly named
function such as __prop_get_hours() would cause it to be called instead of
returning the property.
Only when the property does not exist, just like it is with __get
- Currently __get() is only checked/invoked if there is not a property
already defined; ie properties shadow __get() (no performance penalty)
Right. I would expect / hope for __prop_get_XXX to work exactly the same.
- It would dramatically reduce performance because every property access
would have to create the function string, get it's hash value and .....
But that only applies to an "accessor shadows property" doctrine, and that
is one of these complications / complexity issues which makes me prefer
the "property exists means it's definite" doctrine as already deployed with
__get.
best regards
Patrick
Hi!
That's why I think they shouldn't even be visible to users, they aren't
relevant to them and in fact it could mis-lead them into thinking that
they could simply define __getHours() and expect $foo->Hours to call
it, which it wouldn't.
I think it should. That's how __get works.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by
an accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor they
expect to see an accessor, reflection should reflect that there are
accessors and no other "methods" they did not explicitly define. If
they were to reflect on all of the methods of their class and see a
number of __getHours() they may be confused as to why or where this
function came from. From their perspective, they have defined an
accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want to
see an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information available
to you. You would probably not be confused if you wrote $obj?abc = 1
and got back an error like "Fatal Error: Class->__setAbc() function
does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
Speaking as a user-land programmer that's been following this thread,
but hasn't been able to jump in yet due to the high volume of comments...
What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
-
Should I have a mental model of this being some syntax candy on top
of existing properties? Vis, this is just a short-hand for bean-style
classes? By Bean style, I mean Properties that would be public but
aren't because Public Is Bad(tm), so instead we have getX()/setX() for
every property, so that we can still use the object like a struct rather
than an object but still say we're using methods even though we've just
reimplemented public properties with more verbose syntax. (Note: Yes, I
know that's a rather harsh and judgmental description. I happen to
firmly dislike Bean-style objects.) -
Should I have a mental model that these fancy-pants properties are
some different third thingie on objects, distinct from traditional data
members and methods?
Right now I'm not sure which mental model I'm supposed to use, and I get
the sense that there's no clear consensus on that question yet. That, I
think, is the key question, and will inform how things like Reflection
should expose data about this new syntax.
For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of an
object/class, separate from traditional data members and methods. Then
it's consistently a third thingie. If, however, I'm supposed to think
of it as just a short-hand syntax for writing a bean, then I'd expect it
to be presented to me as if I'd hand-written all of the stuff that this
syntax is emulating. Vis, methods show up as methods, and anything I'd
be able to read/write directly without going through an intermediary
method should show up as a property just as it does now.
Note: I'm speaking here of the mental model of the user, which does not
necessarily have any relationship to the implementation details. If I'm
"supposed" to think of it as a third thingie, it doesn't matter that it
may be implemented internally as syntactic sugar. It should be
presented to me as a third thingie, consistently, with the engine
internal implementation details completely irrelevant. (Which means
they can be changed later if needs be.)
I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the rest
of these discussions.
--Larry Garfield
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by
an accessor declaration should be invisible and non-callable
directly. Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor they
expect to see an accessor, reflection should reflect that there are
accessors and no other "methods" they did not explicitly define. If
they were to reflect on all of the methods of their class and see a
number of __getHours() they may be confused as to why or where this
function came from. From their perspective, they have defined an
accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want
to see an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information available
to you. You would probably not be confused if you wrote $obj?abc = 1
and got back an error like "Fatal Error: Class->__setAbc() function
does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
Speaking as a user-land programmer that's been following this thread,
but hasn't been able to jump in yet due to the high volume of comments...What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
Should I have a mental model of this being some syntax candy on top
of existing properties? Vis, this is just a short-hand for bean-style
classes? By Bean style, I mean Properties that would be public but
aren't because Public Is Bad(tm), so instead we have getX()/setX() for
every property, so that we can still use the object like a struct
rather than an object but still say we're using methods even though
we've just reimplemented public properties with more verbose syntax.
(Note: Yes, I know that's a rather harsh and judgmental description.
I happen to firmly dislike Bean-style objects.)Should I have a mental model that these fancy-pants properties are
some different third thingie on objects, distinct from traditional
data members and methods?Right now I'm not sure which mental model I'm supposed to use, and I
get the sense that there's no clear consensus on that question yet.
That, I think, is the key question, and will inform how things like
Reflection should expose data about this new syntax.For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of an
object/class, separate from traditional data members and methods.
Then it's consistently a third thingie. If, however, I'm supposed to
think of it as just a short-hand syntax for writing a bean, then I'd
expect it to be presented to me as if I'd hand-written all of the
stuff that this syntax is emulating. Vis, methods show up as methods,
and anything I'd be able to read/write directly without going through
an intermediary method should show up as a property just as it does now.Note: I'm speaking here of the mental model of the user, which does
not necessarily have any relationship to the implementation details.
If I'm "supposed" to think of it as a third thingie, it doesn't matter
that it may be implemented internally as syntactic sugar. It should
be presented to me as a third thingie, consistently, with the engine
internal implementation details completely irrelevant. (Which means
they can be changed later if needs be.)I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the
rest of these discussions.--Larry Garfield
Addendum: If model 2 (third distinct thingie) is how I'm supposed to be
thinking of them, then perhaps an additional keyword is needed to help
drive that point home. Vis:
class Foo {
// Data member, directly accessible.
public $bar;
// Clearly a different type of thingie than $bar.
public property $baz {
get() { return $this->baz; }
set($value) { $this->baz = $value;}
}
// A method as we know and love them.
public function beep() {}
}
Of course, that should only be used if the mental model is that they're
a distinct thingie. If it's just syntactic sugar (again, mental model,
not implementation), then a new keyword is a bad idea.
--Larry Garfield
Hey Larry,
Glad you chimed in here on this. I my opinion (author of thingy), they
are separate and distinct from data members. More specifically they
are getter and setter code that is called when the property is accessed.
Using your example:
echo $obj->baz; // executes the code "return $this->baz;"
and
$obj->baz = 4; // executes the code "$this->baz = $value;"
So from the perspective of the user of the class, they are just
"properties" but internal to the class they are implemented with
methods and code.
I think everyone would agree that your #1 is definitely not right,
however I believe there is not consensus on whether or not these are
different from properties. To the consumer of the class, they are no
different than properties, to the author of the class they are very
different.
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated
by an accessor declaration should be invisible and non-callable
directly. Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor
they expect to see an accessor, reflection should reflect that there
are accessors and no other "methods" they did not explicitly define.
If they were to reflect on all of the methods of their class and see
a number of __getHours() they may be confused as to why or where
this function came from. From their perspective, they have defined
an accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want
to see an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information
available to you. You would probably not be confused if you wrote
$obj?abc = 1 and got back an error like "Fatal Error:
Class->__setAbc() function does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
Speaking as a user-land programmer that's been following this thread,
but hasn't been able to jump in yet due to the high volume of
comments...What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
Should I have a mental model of this being some syntax candy on
top of existing properties? Vis, this is just a short-hand for
bean-style classes? By Bean style, I mean Properties that would be
public but aren't because Public Is Bad(tm), so instead we have
getX()/setX() for every property, so that we can still use the object
like a struct rather than an object but still say we're using methods
even though we've just reimplemented public properties with more
verbose syntax. (Note: Yes, I know that's a rather harsh and
judgmental description. I happen to firmly dislike Bean-style objects.)Should I have a mental model that these fancy-pants properties are
some different third thingie on objects, distinct from traditional
data members and methods?Right now I'm not sure which mental model I'm supposed to use, and I
get the sense that there's no clear consensus on that question yet.
That, I think, is the key question, and will inform how things like
Reflection should expose data about this new syntax.For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of
an object/class, separate from traditional data members and methods.
Then it's consistently a third thingie. If, however, I'm supposed to
think of it as just a short-hand syntax for writing a bean, then I'd
expect it to be presented to me as if I'd hand-written all of the
stuff that this syntax is emulating. Vis, methods show up as
methods, and anything I'd be able to read/write directly without
going through an intermediary method should show up as a property
just as it does now.Note: I'm speaking here of the mental model of the user, which does
not necessarily have any relationship to the implementation details.
If I'm "supposed" to think of it as a third thingie, it doesn't
matter that it may be implemented internally as syntactic sugar. It
should be presented to me as a third thingie, consistently, with the
engine internal implementation details completely irrelevant. (Which
means they can be changed later if needs be.)I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the
rest of these discussions.--Larry Garfield
Addendum: If model 2 (third distinct thingie) is how I'm supposed to
be thinking of them, then perhaps an additional keyword is needed to
help drive that point home. Vis:class Foo {
// Data member, directly accessible.
public $bar;// Clearly a different type of thingie than $bar.
public property $baz {
get() { return $this->baz; }
set($value) { $this->baz = $value;}
}// A method as we know and love them.
public function beep() {}}
Of course, that should only be used if the mental model is that
they're a distinct thingie. If it's just syntactic sugar (again,
mental model, not implementation), then a new keyword is a bad idea.--Larry Garfield
--
-Clint
See, I'm not convinced that "everyone would agree that #1 [just some
syntax candy] is definitely not right". From the discussion here, it
seems like some are still thinking of it that way.
If they are supposed to be a 3rd thingie, and the only relation to data
members as we've known them is that they have the same external syntax,
then IMO we should make them as distinct as possible, everywhere. New
keyword, separate reflection pipeline, the works. That then means that
the implementation detail of "public $baz { get() {return 'meep'; }
causes the creation of public function __get_property_meep()" should not
be exposed, anywhere, and that method should not show up in reflection,
since it doesn't really exist, it's just an implementation detail.
It's the "depending on how you look at it, you may or may not get to see
implementation details leak" problem that I think is the worst case
scenario.
--Larry Garfield
Hey Larry,
Glad you chimed in here on this. I my opinion (author of thingy),
they are separate and distinct from data members. More specifically
they are getter and setter code that is called when the property is
accessed.Using your example:
echo $obj->baz; // executes the code "return $this->baz;"
and
$obj->baz = 4; // executes the code "$this->baz = $value;"
So from the perspective of the user of the class, they are just
"properties" but internal to the class they are implemented with
methods and code.I think everyone would agree that your #1 is definitely not right,
however I believe there is not consensus on whether or not these are
different from properties. To the consumer of the class, they are no
different than properties, to the author of the class they are very
different.I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated
by an accessor declaration should be invisible and non-callable
directly. Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor
they expect to see an accessor, reflection should reflect that there
are accessors and no other "methods" they did not explicitly define.
If they were to reflect on all of the methods of their class and see
a number of __getHours() they may be confused as to why or where
this function came from. From their perspective, they have defined
an accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want
to see an error like: Warning, cannot set Class?abc, no setter
defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information
available to you. You would probably not be confused if you wrote
$obj?abc = 1 and got back an error like "Fatal Error:
Class->__setAbc() function does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
Speaking as a user-land programmer that's been following this thread,
but hasn't been able to jump in yet due to the high volume of
comments...What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
Should I have a mental model of this being some syntax candy on
top of existing properties? Vis, this is just a short-hand for
bean-style classes? By Bean style, I mean Properties that would be
public but aren't because Public Is Bad(tm), so instead we have
getX()/setX() for every property, so that we can still use the object
like a struct rather than an object but still say we're using methods
even though we've just reimplemented public properties with more
verbose syntax. (Note: Yes, I know that's a rather harsh and
judgmental description. I happen to firmly dislike Bean-style objects.)Should I have a mental model that these fancy-pants properties are
some different third thingie on objects, distinct from traditional
data members and methods?Right now I'm not sure which mental model I'm supposed to use, and I
get the sense that there's no clear consensus on that question yet.
That, I think, is the key question, and will inform how things like
Reflection should expose data about this new syntax.For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of
an object/class, separate from traditional data members and methods.
Then it's consistently a third thingie. If, however, I'm supposed to
think of it as just a short-hand syntax for writing a bean, then I'd
expect it to be presented to me as if I'd hand-written all of the
stuff that this syntax is emulating. Vis, methods show up as
methods, and anything I'd be able to read/write directly without
going through an intermediary method should show up as a property
just as it does now.Note: I'm speaking here of the mental model of the user, which does
not necessarily have any relationship to the implementation details.
If I'm "supposed" to think of it as a third thingie, it doesn't
matter that it may be implemented internally as syntactic sugar. It
should be presented to me as a third thingie, consistently, with the
engine internal implementation details completely irrelevant. (Which
means they can be changed later if needs be.)I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the
rest of these discussions.--Larry Garfield
Addendum: If model 2 (third distinct thingie) is how I'm supposed to
be thinking of them, then perhaps an additional keyword is needed to
help drive that point home. Vis:class Foo {
// Data member, directly accessible.
public $bar;// Clearly a different type of thingie than $bar.
public property $baz {
get() { return $this->baz; }
set($value) { $this->baz = $value;}
}// A method as we know and love them.
public function beep() {}}
Of course, that should only be used if the mental model is that
they're a distinct thingie. If it's just syntactic sugar (again,
mental model, not implementation), then a new keyword is a bad idea.--Larry Garfield
--
-Clint
I would say that the proposed accessors is what we should have added back
then instead of __get/__set . The problem is that now we will have two
similar (albeit one is an ugly subset of the other) feature which needs to
co-exists.
My gut tells me that we should ditch the magic method approach with the
introduction of accessors and provide easy/automated migration.
Ofc. that would mean that we need at least one major version.
My two cents from the sidelines.
2012.10.28. 3:39, "Larry Garfield" larry@garfieldtech.com ezt írta:
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2 change
spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-
implemented/change-requestshttps://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests------------------------------------------------------------
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly. Others
are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php works,
only how their own code works. If they define an accessor they expect to
see an accessor, reflection should reflect that there are accessors and no
other "methods" they did not explicitly define. If they were to reflect on
all of the methods of their class and see a number of __getHours() they may
be confused as to why or where this function came from. From their
perspective, they have defined an accessor and "how" that accessor works on
the inside is of no importance to them and only seeks to complicate or
confuse matters when they are exposed to these "implementation details" of
the php language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want to see
an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic, then
you want to see them, you want to call them directly if you so choose. In
effect you want nothing hidden from you. In this case you probably don't
even want Reflection to reflect accessors as anything different than
specially formatted and called methods on the class. This can be
understandable because you want all information available to you. You would
probably not be confused if you wrote $obj?abc = 1 and got back an error
like "Fatal Error: Class->__setAbc() function does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them confused,
possibly frustrated and likely asking about it to the internals mailing
list to answer (repeatedly).
------------------------------------------------------------Thoughts?
Speaking as a user-land programmer that's been following this thread, but
hasn't been able to jump in yet due to the high volume of comments...What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
Should I have a mental model of this being some syntax candy on top of
existing properties? Vis, this is just a short-hand for bean-style
classes? By Bean style, I mean Properties that would be public but aren't
because Public Is Bad(tm), so instead we have getX()/setX() for every
property, so that we can still use the object like a struct rather than an
object but still say we're using methods even though we've just
reimplemented public properties with more verbose syntax. (Note: Yes, I
know that's a rather harsh and judgmental description. I happen to firmly
dislike Bean-style objects.)Should I have a mental model that these fancy-pants properties are some
different third thingie on objects, distinct from traditional data members
and methods?Right now I'm not sure which mental model I'm supposed to use, and I get
the sense that there's no clear consensus on that question yet. That, I
think, is the key question, and will inform how things like Reflection
should expose data about this new syntax.For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of an
object/class, separate from traditional data members and methods. Then
it's consistently a third thingie. If, however, I'm supposed to think of
it as just a short-hand syntax for writing a bean, then I'd expect it to be
presented to me as if I'd hand-written all of the stuff that this syntax is
emulating. Vis, methods show up as methods, and anything I'd be able to
read/write directly without going through an intermediary method should
show up as a property just as it does now.Note: I'm speaking here of the mental model of the user, which does not
necessarily have any relationship to the implementation details. If I'm
"supposed" to think of it as a third thingie, it doesn't matter that it may
be implemented internally as syntactic sugar. It should be presented to me
as a third thingie, consistently, with the engine internal implementation
details completely irrelevant. (Which means they can be changed later if
needs be.)I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the rest of
these discussions.--Larry Garfield
There are still use cases for __get(), when the list of internal
properties is dynamic. We're actually leveraging that for Drupal 8's
entity system. Removing it would be a big problem. :-)
But that still doesn't resolve the mental model question.
--Larry Garfield
I would say that the proposed accessors is what we should have added back
then instead of __get/__set . The problem is that now we will have two
similar (albeit one is an ugly subset of the other) feature which needs to
co-exists.
My gut tells me that we should ditch the magic method approach with the
introduction of accessors and provide easy/automated migration.
Ofc. that would mean that we need at least one major version.
My two cents from the sidelines.
2012.10.28. 3:39, "Larry Garfield" larry@garfieldtech.com ezt írta:I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2 change
spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-
implemented/change-requestshttps://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests------------------------------------------------------------
Some people are in favor of the internal functions being generated by an
accessor declaration should be invisible and non-callable directly. Others
are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php works,
only how their own code works. If they define an accessor they expect to
see an accessor, reflection should reflect that there are accessors and no
other "methods" they did not explicitly define. If they were to reflect on
all of the methods of their class and see a number of __getHours() they may
be confused as to why or where this function came from. From their
perspective, they have defined an accessor and "how" that accessor works on
the inside is of no importance to them and only seeks to complicate or
confuse matters when they are exposed to these "implementation details" of
the php language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want to see
an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic, then
you want to see them, you want to call them directly if you so choose. In
effect you want nothing hidden from you. In this case you probably don't
even want Reflection to reflect accessors as anything different than
specially formatted and called methods on the class. This can be
understandable because you want all information available to you. You would
probably not be confused if you wrote $obj?abc = 1 and got back an error
like "Fatal Error: Class->__setAbc() function does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them confused,
possibly frustrated and likely asking about it to the internals mailing
list to answer (repeatedly).
------------------------------------------------------------Thoughts?
Speaking as a user-land programmer that's been following this thread, but
hasn't been able to jump in yet due to the high volume of comments...What's unclear to me is what my mental model should be for this new
syntax. That's important for informing how it should be exposed to me.
Should I have a mental model of this being some syntax candy on top of
existing properties? Vis, this is just a short-hand for bean-style
classes? By Bean style, I mean Properties that would be public but aren't
because Public Is Bad(tm), so instead we have getX()/setX() for every
property, so that we can still use the object like a struct rather than an
object but still say we're using methods even though we've just
reimplemented public properties with more verbose syntax. (Note: Yes, I
know that's a rather harsh and judgmental description. I happen to firmly
dislike Bean-style objects.)Should I have a mental model that these fancy-pants properties are some
different third thingie on objects, distinct from traditional data members
and methods?Right now I'm not sure which mental model I'm supposed to use, and I get
the sense that there's no clear consensus on that question yet. That, I
think, is the key question, and will inform how things like Reflection
should expose data about this new syntax.For instance, if model 2 is how I'm supposed to be thinking, then I'd
expect I'd need a third reflection object for getting things off of an
object/class, separate from traditional data members and methods. Then
it's consistently a third thingie. If, however, I'm supposed to think of
it as just a short-hand syntax for writing a bean, then I'd expect it to be
presented to me as if I'd hand-written all of the stuff that this syntax is
emulating. Vis, methods show up as methods, and anything I'd be able to
read/write directly without going through an intermediary method should
show up as a property just as it does now.Note: I'm speaking here of the mental model of the user, which does not
necessarily have any relationship to the implementation details. If I'm
"supposed" to think of it as a third thingie, it doesn't matter that it may
be implemented internally as syntactic sugar. It should be presented to me
as a third thingie, consistently, with the engine internal implementation
details completely irrelevant. (Which means they can be changed later if
needs be.)I don't know which mental model is intended, nor which one would be
better, but that is, I believe, the question that should inform the rest of
these discussions.--Larry Garfield
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.
I would propose that:
- Internal accessor methods that are defined are callable directly.
- Said methods are not reflected or revealed by the engine (stack
traces, reflection, etc would hide the engines implementation details)
I think that with the above, #1 makes it easy as no further changes are
required to make that happen, they're already directly callable and #2
jives with what most userland programmers would expect.
Anyone disagree?
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by
an accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor they
expect to see an accessor, reflection should reflect that there are
accessors and no other "methods" they did not explicitly define. If
they were to reflect on all of the methods of their class and see a
number of __getHours() they may be confused as to why or where this
function came from. From their perspective, they have defined an
accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want to
see an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information available
to you. You would probably not be confused if you wrote $obj?abc = 1
and got back an error like "Fatal Error: Class->__setAbc() function
does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
--
-Clint
@ internal accessor method visibility / callability
I would prefer "Type 1" because:
- A programming language is made for those who use the language not for those who develop this language. What is the target group of PHP?
- Why should I define a property "protected $property { }" and call it via ->__getProperty() ? If I would like to do that, I can define "public function __getProperty() { }"
- The feature provides property accessors and not magic method generators
- Providing internal accessor method callability could make code less readable and more complex, without adding any plus
- This magic behavior blows up documentation and will make the whole topic more complicated for "beginners"
- What happens if I define "protected $property { get() {...} }" and "protected function __getProperty() { }" in one class?
I hope that does not sound aggressive ;)
Best regards
Christian
-----Original Message-----
From: Clint Priest [mailto:cpriest@zerocue.com]
Sent: Wednesday, November 14, 2012 2:28 PM
To: PHP Developers Mailing List
Subject: Re: [PHP-DEV] [RFC] Property Accessors v1.2 : Internal Accessor Method Visibility / Callability
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.
I would propose that:
- Internal accessor methods that are defined are callable directly.
- Said methods are not reflected or revealed by the engine (stack
traces, reflection, etc would hide the engines implementation details)
I think that with the above, #1 makes it easy as no further changes are
required to make that happen, they're already directly callable and #2
jives with what most userland programmers would expect.
Anyone disagree?
I'm opening up several new threads to get discussion going on the
remaining "being debated" categories referenced in this 1.1 -> 1.2
change spec:
https://wiki.php.net/rfc/propertygetsetsyntax-as-implemented/change-requests
Some people are in favor of the internal functions being generated by
an accessor declaration should be invisible and non-callable directly.
Others are in favor of leaving them visible and callable.Type 1 ( Userland Programmer )*
As a userland programmer, someone who cares nothing for "how" php
works, only how their own code works. If they define an accessor they
expect to see an accessor, reflection should reflect that there are
accessors and no other "methods" they did not explicitly define. If
they were to reflect on all of the methods of their class and see a
number of __getHours() they may be confused as to why or where this
function came from. From their perspective, they have defined an
accessor and "how" that accessor works on the inside is of no
importance to them and only seeks to complicate or confuse matters
when they are exposed to these "implementation details" of the php
language its-self. If you tried to set a value such as $obj?abc = 1
through an accessor which could not be set, you would probably want to
see an error like: Warning, cannot set Class?abc, no setter defined.Type 2 ( Internals Programmer )*
As an internals programmer, you want nothing hidden from you. If an
accessor implements special __getHours() methods to work its magic,
then you want to see them, you want to call them directly if you so
choose. In effect you want nothing hidden from you. In this case you
probably don't even want Reflection to reflect accessors as anything
different than specially formatted and called methods on the class.
This can be understandable because you want all information available
to you. You would probably not be confused if you wrote $obj?abc = 1
and got back an error like "Fatal Error: Class->__setAbc() function
does not exist.Unfortunately 80 to 95% of all people who use PHP are of the first
type.*
Revealing these internal matters to them would only leave them
confused, possibly frustrated and likely asking about it to the
internals mailing list to answer (repeatedly).Thoughts?
--
-Clint
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.
I got the feeling that in the last few mails we actually made some progress
and some people agreed with me that __magic accessor methods and a
dedicated syntax for them are not combinable semantically. Maybe I got that
wrong :/
I would propose that:
- Internal accessor methods that are defined are callable directly.
- Said methods are not reflected or revealed by the engine (stack traces,
reflection, etc would hide the engines implementation details)I think that with the above, #1 makes it easy as no further changes are
required to make that happen, they're already directly callable
The current implementation just uses the __ methods internally, but they
are not actually magic accessor methods. That's not what Stas wants (as far
as I understood). So you would still have to change the implementation to
make them true magic methods which can be used independently from the
special accessor syntax.
and #2 jives with what most userland programmers would expect.
So with your current plan we would end up with this:
a) A dedicated accessors syntax
b) which internally stores the accessors as methods with special names
c) but those methods are not magic methods, so you can't get the same
behavior by defining them directly
d) and the methods are hidden from the user
e) but he can still call them (even though they don't exist if he asks for
them in reflection).
All this sounds very odd to me.
Nikita :)
On Wednesday 14 November 2012 16:35:31 Nikita Popov wrote:
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.I got the feeling that in the last few mails we actually made some progress
and some people agreed with me that __magic accessor methods and a
dedicated syntax for them are not combinable semantically. Maybe I got that
wrong :/
I thought I'd made a proposal that would solve that problem, but maybe it was
overlooked, or more likely too ugly to be recognized as such.
Requires a single new feature / syntax, that at least I find missing right
now:
class ... {
no methodname();
// or
no $property;
}
removing the specified thing from the class, with the possibility to then
redefine it. Silently ignore this when the thing doesn't exist.
The mechanism for that could then be used to solve your semantic puzzle, using
these rules:
- any ordinary property declaration for $foo internally also does
no __prop_get_foo();
no __prop_set_foo();
no __prop_isset_foo();
no __prop_unset_foo(); - any declaration of these four new magic methods internally also does
no $foo;
In other words:
whenever a class implements one of the accessor magic methods, an inherited
property is ignored, as if it wasn't present in the base class(es) in the
first place.
And whenever a class declares a property in the ordinary way, any inherited
magic property accessor methods are ignored, as if they were not present in
the base class(es) in the first place.
Maybe a "final" in the respective base class, would make this attempt an
ERROR.
What do you think? Should I try to write up an RFC for the "no" feature?
best regards
Patrick
I thought I'd made a proposal that would solve that problem, but maybe it
was
overlooked, or more likely too ugly to be recognized as such.Requires a single new feature / syntax, that at least I find missing right
now:class ... {
no methodname();
// or
no $property;
}removing the specified thing from the class, with the possibility to then
redefine it. Silently ignore this when the thing doesn't exist.
Removing methods from an extending class is an LSP violation. It shouldn't
be done and I don't know any languages with an object orientation system
similar to PHP that allow this.
I think that this "no" tagging approach wouldn't really solve anything,
just patch it up in some rather ugly way.
Nikita
Am 19.11.2012 16:41 schrieb "Nikita Popov" nikita.ppv@gmail.com:
class ... {
no methodname();
// or
no $property;
}Removing methods from an extending class is an LSP violation.
I see LSP as a best practise for class design, not as something a language
should enforce.
Also, the propsed "autmatic" use of that "no" mechanism to solve the
accessor vs. property precendence issue, wouldn't be an LSP violation by
itself.
Anyway, the use case I sometimes had for that feature wouldn't even violate
LSP. I occasionaly have a subclass which likes to use a ___call magic
method to pass method calls on to a delegate object, and that does not work
for methods declared on the superclass in any way, be it as "throw
subclassresponsibility()" methods or some kind of default implementation
that other sibling classes would profit from. The only way out now is to
leave out such methods in the superclass, put them into a trait, and use
that trait in all subclasses that do not want to delegate.
best regards
Patrick
Yeah, pretty much. I would not say they are "hidden" from the user,
they are simply not revealed purposely. (see example below for reason)
It's an irrelevant engine implementation detail. They would simply be
callable only because they are actually methods. They are not magic
methods because their simple existence does not make them accessors.
Fatal error: Call to private method a::__setb() from context ''...
Or...
Fatal error: Cannot set private property a::$b.
A user seeing the first error after having defined a property would be
like WTF? What is __setb() and why does the engine think I'm trying to
call it?
As the code is currently written, nearly all errors that would have
produced confusing errors such as the former, they produce errors such
as the latter, one that makes sense given that they are trying to set a
property.
Nikita, you and Stas are the two most diametrically opposed on this
issue, would you please hash it out and let me know? You all know my
position on what I think it should do and I'd just like this to get
resolved.
-Clint
On Wed, Nov 14, 2012 at 2:27 PM, Clint Priest <cpriest@zerocue.com
mailto:cpriest@zerocue.com> wrote:Been AWOL for a while and getting back to this, doesn't seem like any resolution has occurred, just the conversation has died down.
I got the feeling that in the last few mails we actually made some
progress and some people agreed with me that __magic accessor methods
and a dedicated syntax for them are not combinable semantically. Maybe
I got that wrong :/I would propose that: 1) Internal accessor methods that are defined are callable directly. 2) Said methods are not reflected or revealed by the engine (stack traces, reflection, etc would hide the engines implementation details) I think that with the above, #1 makes it easy as no further changes are required to make that happen, they're already directly callable
The current implementation just uses the __ methods internally, but
they are not actually magic accessor methods. That's not what Stas
wants (as far as I understood). So you would still have to change the
implementation to make them true magic methods which can be used
independently from the special accessor syntax.and #2 jives with what *most userland programmers* would expect.
So with your current plan we would end up with this:
a) A dedicated accessors syntax
b) which internally stores the accessors as methods with special names
c) but those methods are not magic methods, so you can't get the same
behavior by defining them directly
d) and the methods are hidden from the user
e) but he can still call them (even though they don't exist if he asks
for them in reflection).All this sounds very odd to me.
Nikita :)
--
-Clint
Hi!
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.I would propose that:
- Internal accessor methods that are defined are callable directly.
- Said methods are not reflected or revealed by the engine (stack
traces, reflection, etc would hide the engines implementation details)I think that with the above, #1 makes it easy as no further changes are
required to make that happen, they're already directly callable and #2
jives with what most userland programmers would expect.Anyone disagree?
Yes. I strongly disagree with adding any magic to the engine that messes
with reflection and backtraces and removes methods existing and being
called from it. I think no "userland" programmer would have any problem
understanding that these methods exist and how they work, just as nobody
has problem understanding how __get works. I think adding this magic
complicates both engine code (which will have to be supported for years
to come) and the language, without absolutely any benefit to anybody
except for imaginary people being scared to death by methods that they
themselves defined showing up in the backtrace.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
sigh
Which error would make more sense to you Stas...
Given this code:
class a {
public $b {
get() { return 5; }
private set($x) { /* do something */ }
}
}
$o = new a();
echo $o->b;
$o->b = 42;
There are two possibilities at this point. The code base, without all
the work I have done to make the errors make sense will show:
Fatal error: Call to private method a::__setb() from context ''...
Or...
Fatal error: Cannot set private property a::$b.
Which makes more sense to the most people?
Hi!
Been AWOL for a while and getting back to this, doesn't seem like any
resolution has occurred, just the conversation has died down.I would propose that:
- Internal accessor methods that are defined are callable directly.
- Said methods are not reflected or revealed by the engine (stack
traces, reflection, etc would hide the engines implementation details)I think that with the above, #1 makes it easy as no further changes are
required to make that happen, they're already directly callable and #2
jives with what most userland programmers would expect.Anyone disagree?
Yes. I strongly disagree with adding any magic to the engine that messes
with reflection and backtraces and removes methods existing and being
called from it. I think no "userland" programmer would have any problem
understanding that these methods exist and how they work, just as nobody
has problem understanding how __get works. I think adding this magic
complicates both engine code (which will have to be supported for years
to come) and the language, without absolutely any benefit to anybody
except for imaginary people being scared to death by methods that they
themselves defined showing up in the backtrace.
--
-Clint
Hi!
Fatal error: Call to private method a::__setb() from context ''...
Or...
Fatal error: Cannot set private property a::$b.
Which makes more sense to the most people?
Either of these is fine. I'm not talking about that though. You said:
"stack traces, reflection, etc would hide the engines implementation
details". That means that every part of the engine that deals with stack
and reflection should be modified, for no reason other than to hide the
scary fact of existence of accessor methods. I think this should not be
done - stack traces should show stack as it is, and that's it.
Reflection should show the methods as they are, and that's it. No
additional complications and special exceptions in order not to hurt the
feelings of (imaginary) easily scared and confused users.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227