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
@mixin to support behaviors/mixins #35
Comments
Yep, this is missing. |
I have discussed this item with @ashnazg and we have come to the conclusion that the added benefit is unclear and whether it weighs up to adding a new tag. Due to this I have come to the conclusion not to include this tag to the PSR at this time. |
The added benefit is extremely clear to me - I am already using it on production code with PhpStorm, and it makes mix-in behaviors so much easier to work with. Previously, every piece of code that works with types that use mix-in behaviors, had be explicitly documented, inline, on a case-by-case basis, like this:
Imagine having hundreds of methods where you need to document the mix-ins explicitly in every single method. Now forget all of that and simply document the behaviors once, for the type itself:
It makes a lot of sense, and I was able to scrap hundreds of redundant inline documentation tags, while still providing the exact same information. There is a lot of value to being able to document things at the root, where they were actually defined, rather than having to document repeatedly and sporadically throughout loosely related code. If you don't see the benefit, you probably haven't worked with mix-in behaviors? As @samdark pointed out, lots of mainstream PHP frameworks use them, which means lots of developers need them - which means this tag can save a ton of work for us. That's a clear benefit. |
This is actually pretty useful, is something similar implemented? Or can this be reviewed? For example, take this Manager class from Laravel: https://github.com/laravel/framework/blob/4.2/src/Illuminate/Support/Manager.php That uses the magic __call() method to redirect all calls to the driver. But the IDE doesn't know that. So if we could use the |
It definitely should be implemented - prior to traits in php 5.4.0, the only option for mix-ins was run-time hocus-pocus, which many frameworks implement in many different varieties, most of which could be documented (and already can in e.g. PhpStorm) using this tag. Since it's already proven useful and already in use, I think you would need a very clear reason not to support it - e.g. there would have to be something wrong with it. There is a clear benefit to somebody (myself included) or it wouldn't have been implemented. I think the name and syntax of the existing tag is fine, it's behavior is pretty easy to understand, and I don't see any shortcomings or reasons not to support it? |
Thanks for providing the additional information; I have reopened this issue so that this can be re-reviewed |
Should there be distinction between just calling the methods (eg. extending multiple classes) and using __callStatic to go from static to the actual instance. |
👍 for implementation of @mixin. It's also very useful in the context of tools like PHPSpec which describe classes while making it available via |
So this is another good example, the Laravel Database Model: https://github.com/laravel/framework/blob/v5.0.16/src/Illuminate/Database/Eloquent/Model.php#L3307-L3338 Calls on the model are redirected to a query instance. Using
But because it's also used statically, it should also be static. So perhaps this?
|
I think that's a really bad example - what Laravel is doing here is extremely unusual: run-time hocus pocus to make instance members of one class appear to be static members of another class. Delegating from static to instance (or instance to static) members is an extremely unusual and exotic thing - correct me if I'm wrong, but I don't think I have ever seen any other framework but Laravel doing that. (?) Under any circumstances, an annotation that delegates static to instance (or instance to static) would have some really strange implications in practice, since classes can have a mix of static and instance members... for starters, what happens to members that are already static? Do they get mixed in or not? You can't say for sure - it isn't even something you can know without running the code. Trying to define this in a declarative, static manner doesn't really make any sense at all. |
Removed my last post - missed some of the context of the thread. |
@mindplay-dk Is it the role of PHPDoc to dictate how code should be structured though? To me it should allow you to properly document any kind of code, up to old legacy code doing weird things or edge cases, testing specs etc. The purpose of this PSR is to standardise what has been done in the wild for years now – if @mixin is part of that and is commonly used, which is the case, to me it should be part of the PSR |
@Anahkiasen I'm not arguing aganist |
@mindplay-dk Wouldn't the "static" behaviour just be that all methods included in the mixin could be called statically or as instance methods .. as opposed to omitting the flag which would result in just instance methods being available? |
For the record: I have completely changed my mind about the validity of |
That's just one option - the problem is, there are any number of possible patterns to delegate calls at run-time, we can't possibly predict or support them all. For example, you could implement I started writing up the spec for Should we even concern ourselves with mixins still? I know that e.g. Yii still uses them, but is that just a "phase"? Until PHP with trait support is generally available with no more need for run-time tricks? If we consider this obsolete practice (and I'm not saying we do, I'm asking!) do we want to support or encourage that? |
Another reason mixin is useful is from the trait's perspective. I have a base |
I would like to see something like @mixin become part of the standard. See: https://github.com/php-integrator/atom-autocompletion/issues/86 |
@MarkVaughn Interesting point, but can't you already solve this by declaring an abstract method inside your trait? That gives you autocompletion and proper checking in PHP itself without the need for a new tag: <?php
class A
{
public function foo() { echo "Hello"; }
}
trait T
{
abstract public function foo(); // Add this to match the expected methods.
public function bar() { echo $this->foo() . " World"; }
}
class B extends A
{
use T;
}
$b = new B();
$b->bar(); If you were to use the trait in another class where you forgot to add the method, you may not notice the error until later as there is no checking on a mixin tag. By using an abstract method, you clearly document that your trait requires additional functionality from the class using it. Also: I don't intend to provide any positive or negative feedback on the |
@Gert-dev That's fine for a few methods but if you access more methods from the base class than that then you constantly need to keep the signatures up to date and it adds a lot of useless boilerplate that is only there for the sake of IDE autocompletion |
@Anahkiasen That is true, it does require extra maintenance from the developer. I've been thinking about this for a while and, even though I agree that To rephrase: you need a trait that can somehow only be used by classes that expose certain functionality and that can assume that functionality is present. That sounds an awful lot like what an interface does for classes. Would it thus not be even more interesting if you could somehow indicate that a trait can only be used by classes implementing a specific interface? interface I
{
public function foo();
}
class B implements I
{
public function foo() { }
}
class C extends B
{
use T;
}
/**
* @requires I
*/
trait T
{
public function bar()
{
$this->foo(); // foo is autocompleted since T can only be used in classes implementing I.
}
} You'd get everything you're looking for:
The downside is that it would not be possible to access class properties directly, but you can fix that by placing a getter in the interface instead. As a bonus, because of this encapsulation, that also allows other classes to retrieve this information from another source than their properties instead. |
An interface is just a fully abstract class, restricting this feature to interfaces only thus makes no sense since there is no difference between interfaces and (abstract) classes after all from the viewpoint of a trait at this point. I requested a similar feature for PhpDoc and PHP. Facebook's Hack has this ability built-in btw. However, internals do not seem to care and see too many problems with supporting this feature. The |
There is one difference though - you cannot type-check against traits, but you can type-check against an abstract base-class, so in that sense there is an important distinction: interfaces and classes are types, and traits are not; they're an implementation detail of which client code is always, by definition, unaware. That said, I agree that I would once again favor modern PHP rather than favoring "clever" frameworks that managed to implement their own "traits" and "behaviors" prior to actual traits. (and, yes, I understand that |
Hi. @mvriel. Any chance this can be looked at again? |
Ping @ondrejmirtes @muglug @neuro159 @mindplay-dk @GaryJones @mvriel @jaapio for opinions. Can folks chime in now on what in-the-wild implementations there are for this? Has it already converged into a single syntax that's utilized the same across implementations? |
If this needs to be pursued further, please bring this up as a new thread on the FIG mailing list for discussion -- https://groups.google.com/forum/#!forum/php-fig |
Recent PhpStorm EAP supports
@mixin
. It's used the same way as “use trait” except that target can be any class.Behaviors/mixins are used in CakePhp, Symfony, Propel, Nette, Yii and Doctrine so it's quite common. Would be great if these will be documented.
Here's the IDE issue history: http://youtrack.jetbrains.com/issue/WI-1730
The text was updated successfully, but these errors were encountered: