Stas,
I'm not sure I understand why it is good to have this. This way of > checking interfaces is very expensive (since you need to scan the > function table) and relies on function names instead of explicit > programmer's intent to validate the API (i.e. it assumes if two classes > have method named open() this method does the same thing and the classes > can be used interchangeably). Since you can easily add "implements" to > your class to declare implementation of a specific protocol, why you > need less safe and more computationally expensive way? > See my reply to Laruence, it's not more expensive... As far as relying on function names instead of programmer's intent, that's absolutely true. It's (at least partially) called Duck Typing, and it's a perfectly valid practice with a lot of practicers. As far as "you can easily add implements", that ignores the relationship where you may not own all of your code. I know I've been in many situations where I've "just needed to add an interface" to a class, except that I didn't own that class. Which led me to either drop the type-hint entirely, or do some nasty work-around. > Explicit declaration of interface has value way beyond mere checking > function names - it is a contract that you agree to when you write > "implements ThisInterface". Absent that, you code starts making > assumptions that are very dangerous. > Yes, "implementing an interface" is about more than just validating APIs. Which is why this proposal doesn't intend to replace the existing functionality. Instead it augments it. It opens the possibilities for more flexible behavior when you need it, instead of simply boxing everything into the dogma of contract-style development (which for the record, I am a fan of)... > Taking the example of the logger here, suppose I make my logger classes > work with this API: $log->error(...), $log->info(...), $log->debug(...). > Pretty standard way of doing it. This is usually done by __call. Now, > when I declare that class implements Logger, I either require __call or > just rely on the fact that if you said "implements Logger" then you know > what "Logger" means and that it should accept the methods above and do > the right thing. However, if I use "protocol typing" (please dispose > with "hinting", we really should stop dragging around this unfortunate > misnomer) then what would we look for in such class? Would we just > accept any class? Any class that implements __call? > Why not? Seriously, why not? Remember, our compiler is not running through every possible permutation of objects to try to figure out which can be fed where. The object still has to come from a programmer wiring it in at some stage. And if a programmer decides that they want a class which implements __call to resolve for their particular method, why is that a bad thing? And if you're maintaining a library where you just care that there's an object that has __call, then let the user pass any class. Why bother type-hinting against a specific interface when all you really care about is the method... This gets down to a deeper philosophy. Control when you need it, but freedom where you don't. Not everyone is going to want to program like this. But the point is that a lot of people do today, and why not offer some engine level help to them...? Also this setup would be rather fragile as absent formal declaration of > interface in the implementing class, it is very easy to miss changes in > the interface, and since there's no explicit link between implementing > class and the interface, no tool can warn you about that change in the > interface until you try to use the object and it starts failing. With > explicit declaration any good IDE will tell you your implementation is > missing a method, and even missing that you'd be told about the class no > longer being good immediately on loading, not when you try to use it. > Absolutely! Which is why there are two very important things to keep in mind here: 1. Protocols are intended to resolve a minimal interface. You should hint against the smallest possible area that your particular method/class needs. If your function only calls a single method, then the protocol hint interface should have only that single method (within reason at least). This is an application of the Interface Segregation Principle. You should keep interfaces as small and narrow and purpose built as possible. 2. Yes, it does limit the usefulness of static analysis. But then again, the vast majority of the PHP language (especially the type system) prevents that already. Considering that the PHP philosophy is that "if it looks like a scalar, it's a string", wouldn't protocols be arguably more along the lines of "the php way" than the current object system? > Also note that unlike the interface check, this check would also force > loading the checked interface (since you can't check the methods without > having it loaded) which provides additional performance drag. > Well, it doesn't really provide a performance drag that isn't already there today. Let's walk through an example: function foo(Bar $bar) { } Let's say you reach that type-hint with an object, but the interface isn't loaded. You're going to raise an error. Because if the interface isn't loaded, you know the object can't implement it. So the error is raised (which kills all performance concerns anyway) function foo(<Bar> $bar) { } Now in this case, we may want to resolve correct even though it's not loaded. So you may *not* get an error, even if the interface isn't already loaded. So yes, the check itself may take longer (since it needs to load the interface), but no longer than the amount of time saved by not having to load the interface at the construction of $bar So in both cases the same total execution time has been spent. The difference is the Protocol check back-loads the time (pushes it to when it's actually used) where the current interface method pre-loads the time (pushes it to the very front of the request). Honestly, I think the lazy method is better, as if I never hint against that interface, I never even load it. Sounds great to me!!! Thanks for the feedback! Anthony