-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add function is_using to check if an object uses a given trait #23
Conversation
Not sure how necessary this is. You can already easily access this information using Reflection:
|
Well is_a and is_subclass_of could also be done through Reflection... |
is_a() and is_subclass_of() are older then reflection. We have since decided to make reflection the primary source for such information. |
What about performance issues when using reflections. Isn't faster to use built in function for checking if the class uses specific trait? Specially in loops when you want to know if specific item has given reflection. |
is_a and is_subclass_of have been marked a no longer deprecated in 5.3.0 and their signatures changed in 5.3.9 meaning that they are still maintened and will be hard to deprecate in a short time. Finally while is_a and is_subclass_of are not necessary for checking the type of a parameter in an object as the developer can use instanceof or typed parameters. Right now there is no easy way to check if a parameter provided to a function uses a given trait... |
Yes, reflection creates an extra object which takes CPU time and memory. I didn't close the PR but stated this to see if there are arguments for adding new global functions. For the mentioned use case a provocative answer: Well, if you have to know it, outside of writing a code documenter/analyzer/.., you're doing something wrong. Traits are "engine level copy and paste" if the runtime behaviour depends on whether the function was written in that class or not you're doing something wrong. Why should we clutter the global namespace if you're doing it wrong? :-) |
I have to admit that php is already cluttered by global functions and it's bad to add new ones. I've got your point with programmer. It's true that he should check class or it's parents but not specific code in the object itself. Also you can use interfaces and check them. It's better to check interface and use trait to implement it's methods. With the global namespace i don't see if there is problem in adding another is_... function. Developers tend to use these functions and they won't know how to check if specific trait is used. |
To further muddle the mix - remember SPL provides "class_uses" - which with a bit of array manipulation can allow you to write a reflectionless version of the reflection code posted above return in_array($trait, class_uses($classname)); All you're doing by NOT making this available is having everyone write their own version of the call |
If there a reason not to make this functionality available via a second argument to <?php
if (class_uses($classnameOrObject, $traitName)) {
// returns bool
}
?> |
I have implemented my previous suggestion in pull request #27 |
@johannes Since a trait can basically be seen as an interface with an implementation, I think it makes sense to have something similar to an As a side note, for example Scala does not have the notion of interfaces, solely traits. |
Adding is_using() seems to make sense when is_a() already exists, and is still maintained & useful. Also adding an equivalent of instanceof ($a usestrait Foo maybe?) could be interesting (I believe it'd be the same code internally). |
This seems odd to me. Traits in the PHP sense are not interfaces. Even if an object "is_using" a trait, it might have aliased method names, and you cannot rely on the trait's methods being present on the object. If you want to make a check like this, you should add an additional interface and implement it in the class using the trait. Then you can check for the interface with instanceof which makes a lot more sense. |
I don't think that traits should be seen as "interface with an implementation". Seeing it as interface causes trouble with aliasing and such stuff. So even if a trait is used it doesn't mean a specific method will be there, it might not be there at all, it might have another name or another visibility. The trait gies no guarantee. If you need some guarantee enforce it by an interface. |
I have not spend much time with the PHP implementation of traits, but I can see your arguments, and if the trait indeed does not guarantee that the method is also present in the object, then I have to second your opinion that this does not make much sense at runtime. This also means that you have to duplicate some code on the interface and in the trait which is unfortunate. |
@naderman I have to agree. You shouldn't ask if specific object uses trait because you can not be sure if methods of that given trait weren't aliased. Therefore it's really bad practice to ask if given object, or class uses trait because you never know how it is used. The question is if programmers should care more about their code and create interfaces, or if php will be more benevolent to them and it will allow them to use is_using instead (or somekind of $object usestrait 'MyTrait'). |
I would like to ask that such proposals are discussed on the internals mailing list. And as Johannes pointed out, the missing guarantees weaken the value of such information. The possibility to change the visibility of a method, to declare it as an implementation detail, will require you to use an interface for the intended purpose. From my point of view, you are not using such checks when you are using PHP as a dynamic language anyway. If somebody knows how to archive this discussion in the bug tracker, this discussion would hopefully help as documentation, and the pull request could be closed. |
allow_string parameter is not a parameter prevents autoloading but restricts 1st parameter as a string, right? Preventing autoload is just a side effect of this. I think the doc is not right. I don't like the way is_a(), is_subclass_of() works now, but it should have consistent doc and behavior. (I fixed docs on SVN yesterday) |
No, like its name says it just allows the first parameter to be a string and does not restrict it. if (allow_string && Z_TYPE_P(obj) == IS_STRING) {
// ...
} else if (Z_TYPE_P(obj) == IS_OBJECT && HAS_CLASS_ENTRY(*obj)) {
// ...
} else {
RETURN_FALSE;
} But as for the autoload yes it is just a side-effect, the method zend_lookup_class used by the string part of the if above uses the autoload by default, the second parameter of the is_a/is_subclass_of methods will never use the autoload whatever value allow_string is used so I agree that the doc is misleading on this. |
Comment on behalf of johannes at php.net: The only reason presented is that one wants to use traits like interfaces. This can't be done as a trait doesn't define a contract. johannes |
I'm confused - I personally use "does this have this trait" to check for BEHAVIOR not as an interface "can I call this method" Often when using things in code (especially other people's code) it is useful to know if there is a trait (behavior) attached to the class - oh this has the log trait, I don't want to inject and use my own logger. Oh this has an event trait, so I don't need to inject it my own event system, etc. |
I don't see how a trait gives any information worth checking (besides documentation and other meta things). I see your idea, Elizabeth, but I fail to see that the existence of a trait gives any relevant information. What I see is that people use traits as "fancy interfaces" and draw wrong conclusions. |
Code is mainly a heavily modified version of is_a/is_subclass_of and provide a test.
Documentation
is_using
(PHP 5.4)
is_using — Checks if the object or class name is using this trait
Description
Checks if the object is using trait trait_name.
Parameters
_object_
_trait___name_
_allow___string_
Return Values
This function returns TRUE if the object object, uses the trait trait_name, FALSE otherwise.
Examples