[RFC] Property Accessors v1.2 : Internal Accessor Method Visibility / Callability

php.internals

Clint M Priest

13 years ago
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

Maciek Sokolewicz

13 years ago
On 26-10-2012 12:37, Clint Priest wrote:
> ------------------------------------------------------------------------ > 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

Steve Clay

13 years ago
On 10/26/12 6:37 AM, Clint Priest wrote:
> 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
-- http://www.mrclay.org/

Stas Malyshev

13 years ago
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

Nikita Popov

13 years ago
On Fri, Oct 26, 2012 at 4:14 PM, Stas Malyshev <smalyshev@sugarcrm.com> wrote:
> 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

Stas Malyshev

13 years ago
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

Nikita Popov

13 years ago
On Fri, Oct 26, 2012 at 10:34 PM, Stas Malyshev <smalyshev@sugarcrm.com> wrote:
> 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

Stas Malyshev

13 years ago
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

Clint M Priest

13 years ago
On 10/26/2012 6:37 PM, Stas Malyshev wrote:
> 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

Stas Malyshev

13 years ago
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

Clint M Priest

13 years ago
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). On 10/27/2012 3:28 PM, Stas Malyshev wrote:
> 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

Stas Malyshev

13 years ago
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

Patrick Schaaf

13 years ago
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

Stas Malyshev

13 years ago
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

Patrick Schaaf

13 years ago
> > - 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 M Priest

13 years ago
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? On Saturday, October 27, 2012 3:01:39 AM, Patrick Schaaf wrote:
>>> - 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

Patrick Schaaf

13 years ago
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 M Priest

13 years ago
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: 1) Currently __get() is only checked/invoked if there is not a property already defined; ie properties shadow __get() (no performance penalty) 2) 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 10/27/2012 2:14 PM, Patrick Schaaf wrote:
> 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

Stas Malyshev

13 years ago
Hi!
> 1) 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.
> 2) 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

Patrick Schaaf

13 years ago
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
> 1) 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.
> 2) 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

Stas Malyshev

13 years ago
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

Larry Garfield

13 years ago
On 10/26/2012 05:37 AM, Clint Priest wrote:
> 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. 1) 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.) 2) 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

Larry Garfield

13 years ago
On 10/27/2012 09:38 PM, Larry Garfield wrote:
> On 10/26/2012 05:37 AM, Clint Priest wrote: >> 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. > > 1) 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.) > > 2) 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 M Priest

13 years ago
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. On Saturday, October 27, 2012 9:48:12 PM, Larry Garfield wrote:
> On 10/27/2012 09:38 PM, Larry Garfield wrote: >> On 10/26/2012 05:37 AM, Clint Priest wrote: >>> 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. >> >> 1) 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.) >> >> 2) 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

Larry Garfield

13 years ago
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 On 10/27/2012 10:59 PM, Clint Priest wrote:

Ferenc Kovacs

13 years ago
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:

Larry Garfield

13 years ago
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 On 10/30/12 3:05 AM, Ferenc Kovacs wrote:

Cal

13 years ago
Le 26/10/2012 11:37, Clint Priest a écrit :
> 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 >
In the RFC, section "read-only / write-only keywords" :
> class TimePeriod{ > private $Seconds; > public $Hours { > get() { return $this->Hours; } > private final set($value) { throw new Exception("Setting > of TimePeriod::$Hours is not allowed."); } > isset() { return isset($this->Seconds); } > unset() { unset($this->Seconds); } > } > }
I just added the methods "isset" and "unset" of the first example. So, is there a case where "set" and "unset" shouldn't have the same visibility ? And "get" and "isset"? If not, the Amaury's proposition could be merged in your syntax:

Clint M Priest

13 years ago
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: 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 and #2 jives with what *most userland programmers* would expect. Anyone disagree? On 10/26/2012 5:37 AM, Clint Priest wrote:
> 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

Christian Stoller

13 years ago
@ internal accessor method visibility / callability I would prefer "Type 1" because: 1. 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? 2. 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() { }" 3. The feature provides *property accessors* and not magic method generators 4. Providing internal accessor method callability could make code less readable and more complex, without adding any plus 5. This magic behavior blows up documentation and will make the whole topic more complicated for "beginners" 6. 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: 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 and #2 jives with what *most userland programmers* would expect. Anyone disagree? On 10/26/2012 5:37 AM, Clint Priest wrote:
> 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 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php

Nikita Popov

13 years ago
On Wed, Nov 14, 2012 at 2:27 PM, Clint Priest <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 :)

Patrick Schaaf

13 years ago
On Wednesday 14 November 2012 16:35:31 Nikita Popov wrote:
> On Wed, Nov 14, 2012 at 2:27 PM, Clint Priest <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 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

Nikita Popov

13 years ago
On Wed, Nov 14, 2012 at 5:24 PM, Patrick Schaaf <php@bof.de> wrote:
> 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

Patrick Schaaf

13 years ago
Am 19.11.2012 16:41 schrieb "Nikita Popov" <nikita.ppv@gmail.com>:
> > On Wed, Nov 14, 2012 at 5:24 PM, Patrick Schaaf <php@bof.de> wrote: > >> 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

Clint M Priest

13 years ago
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 11/14/2012 9:35 AM, Nikita Popov wrote:
> 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

Stas Malyshev

13 years ago
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: > > 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 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

Clint M Priest

13 years ago
*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? On 11/14/2012 10:24 AM, Stas Malyshev wrote:
> 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: >> >> 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 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

Stas Malyshev

13 years ago
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