Note: The voting phase has begun on php.net. If you have an svn account somewhere on php.net, vote and share your opinion: wiki.php.net SPLClassLoader Vote
Recently there has been a rather heated and intense discussion on whether the PSR-0 autoloader "standard" should be included as part of the PHP core (in ext/spl to be exact). I've tried to stay out of the discussion and have successfully done so. Until today. I feel that there's something that's been missing to the discussion. So rather then posting this to the internals list, I feel it's better served by a blog post on the subject. So here's my take on it.
TL;DR: I don't think it should be included in the core.
Why I Am Posting This
This comment on the internals list led me to write this post:With the point to being included in /ext/spl/; is to give a sense of "justification" of this standard and a base in which to push forward.IMHO, that's the exact opposite of a proper justification. That's saying "we want to justify the standard, so include it in the language" instead of what you should be saying in that "the standard is justified, so the language should support it". We're talking about a language level implementation here, not adding capability to the language... It's 100% possible to do everything you need to in PHP code, so it's not like you're adding support for it. You're adding the implementation for it.
I can see 3 main issues with implementing PSR-0 in core at this time:
Issue #1 - It is inconsistent
It does not have any way of handling or even acknowledging edge cases such as the case sensitivity issue that was brought up earlier. Because of that, it has internal inconsistencies with respect to how PHP handles things. This alone should be enough to kill any language level implementation. PHP has enough language level inconsistencies without adding more. At least the current autoloader implementation in the core is consistent in that all filenames are lowercased. PSR-0 doesn't even address that. Sure, you could say that falls under the pervue of coding standards, but that's not the job of the language. The language is supposed to provide implementation without bias. Implementing PSR-0 here would bias the language towards a specific coding syntax and style (considering that if you don't follow that style, it won't work and things will sporadically break on different operating systems). So the argument of `while (consistency) learning_curve--` is actually one for keeping this out of the core since the implementation has several inconsistencies with PHP itself (case sensitivities being the most obvious).Issue #2 - It is not a standard
PSR-0 is not a standard in the true sense of the word. From my knowledge, there was no public RFC for it, and it's missing quite a bit from what other communities require in a standard. First off, there's no listed scope or motivation explicitly listed (which would then nail down what the standard is trying to accomplish). Instead, it's just loosely defined based off the implementation. Secondly, considerations such as security, backwards-compatibility and performance implications are not actually expressed in the standard. This is a major problem since it doesn't even appear that these were considered (most RFCs have these listed explicitly for that reason). Third, there are no acknowledgement or references at all. While this may not seem like an issue, it is because right now there is no way of knowing who to contact or if there was research done to actually justify the standard.Remember, just because some people come to a conclusion doesn't make it a standard. Almost everything we call a standard has had a formal RFC process with all of these steps (Such as RFC2616 and RFC4329). While I think standardizing this is good for the community, I think doing it as a formal standard is extremely important. Why is that? Because a formal RFC shows the community what went into the proposal and exactly what was considered. Right now, the only groups that really knew anything prior to it being accepted were those involved in constructing it. How many non-project developers were talked to or reached out to (in this context, non-project refers to developers who have no vested interest in any open-source (or closed) projects. More those that are developing applications and one-offs, not frameworks)? Were considerations made for those developers who are building one-off or custom implementations? Were considerations made for those who already have implementations on other systems (such as spl_autoload for example)? This wasn't mentioned on any of the php.net lists until May of this year, after it was accepted and when it was asked to be included in the core...
Don't get me wrong, I think that creating standards is great and I don't want to knock the intent of the team that put this together. In fact I think it's very important to do. But now the standard is trying to be pushed into and onto the general community. That's where the problem comes. This "standard" (quotes indicating the above issues with that word) was created informally for and by a subset of developers (realistically, a very small subset). Now that standard is trying to be applied to the community as a whole. It doesn't work that way. It shouldn't work that way. If all the framework developers want to standardize their implementations, more power to them! But if you're looking to enforce that standard beyond the scope of those that created and agree (which you are here), that's when it becomes a problem. The language shouldn't enforce standards of the few. That's not its job. Its job is to support all use cases that it chooses. Given PHP's history, that usecase is pretty well defined, and it's a significantly larger superset of usecases than most frameworks are targeting.
Issue #3 - There's nothing for the core to gain
PSR-0 is not perfect. It doesn't try to be, but it still is not. It's far worse and more counter-productive to force a one-size-fits-all solution on all projects than to take a neutral stance. Aside from enforcing the standard, there is *nothing* practically that will be gained by including it in the core. So I would argue it's more counter-productive to the eco-system to enforce a one-size-fits-all solution that doesn't take into account the needs of the eco-system (frameworks are a very small part of that. A vocal part, but a very small one) than it is to let one or more "standards" exist and be chosen between.Conclusion
In conclusion, let me make one plea:Keep core PHP interests separate from framework interests. PHP is a language with a complete different set of goals and constraints than the frameworks that are developed for it. If they overlap, great. But don't confuse them. They are distinctly different...And apparently I'm not the only one who thinks this way... There are tons of blogs and posts along these lines, include one from @go_oh: Why the PSR-0 Classloader does not belong in SPL. If you have an opinion on this matter, let it be heard! Leave a comment, or write your own post and let me know (I'll keep a list going here if people get back to me on it)...
Edit - Some Explanation Of Inconsistencies Of PSR-0
It seems like people still aren't grasping the inconsistencies with PSR-0 and the rest of the PHP language. Let me go through a few examples...Case Sensitivity
Identifiers in PHP (such as class names) are case insensitive. Some filesystems however are case sensitive (NTFS being the most common, but not the only one). The problem here is that the mapping from PHP identifiers to filesystem identifiers in PSR-0 is case sensitive. So it's completely possible to create code that works on some machines and not others, or that breaks in certain circumstances but not others.Let's say we have a file stored in Foo.php:
new Foo(); new foo();That will work on all systems and at all times with PSR-0. However, if we switch the two around, we run into trouble:
new foo(); new Foo();That will work fine on case insensitive filesystems such as NTFS, but fail on case sensitive ones. So you can develop code that works quite fine on Windows, but when you push to Linux will fail.
Doesn't play nice with other loaders
If a file doesn't exist, PSR-0 doesn't play nice with other autoloaders. It will try to require the file, but then the require will fail and fatal error out. This is a problem since a later autoloader may know how to load it. So it's not following the normal convention of "if you can't load it, don't error out". This is fine if all code that lives in the application follows PSR-0 guidelines, but it makes interoperating with code using a different loader system/standard potentially difficult. Here's an example using the SPLClassLoader specified in PSR-0:Let's say you have a loader defined as new SplClassLoader('foo', '/lib/foo/');. So that would only load classes from `\foo\*` namespace (which is good practice to limit it). Now what happens if I need to add a class to that namespace (such as \foo\bar() stored in /lib/myfoo/foo/bar.php). Note that it's 100% valid and allowed PHP to do so. Now, when I do:
new \foo\bar;What happens depends on the order of the autoloaders. If I load mine first and then the foo one, it will work fine. But if I load the foo one (such as provided by a framework), the whole application will fatal error.
Now, I know you're thinking, "it's not a good idea to do that". But there are examples of cases similar to that happening right now (Kohana for one). The point is, the language supports that 100%. So why add something that could *fail* if you're doing something that's otherwise valid... And we're not talking about just not working, we're talking about throwing a fatal error...
Multiple Classes Map To The Same File
With PSR-0, multiple classes actually map to the same file. For example, all of the following map to the same file (Foo/Bar/Baz.php):- \Foo\Bar\Baz
- \Foo\Bar_Baz
- \Foo_Bar_Baz
So, assuming the three classes didn't all actually live in that one file (for example, they could be autoloaded by another autoloader), consider the following code:
new \Foo\Bar\Baz; new \Foo\Bar_Baz; new \Foo_Bar_Baz;PSR-0 will *not* play nice here. It will try to load the same file 3 times. And when it does, it will fail since it's using require over require_once... So it'll fatal error because it included the same file twice (and get duplicate class definition errors, etc). Something that's 100% valid PHP (those 3 classes are distinct) and can have valid use cases (interacting with PEAR for example) would mysteriously raise unrelated fatal errors...
There are other inconsistencies, but those are more related to how the class is structured itself rather than the "standard" (example: you can set the namespace separator to something that will completely bork other included libraries)...
1. PSR-0 is a well established standard where everybody had the occasion to participate in its definition and implementation. Participation to that group has never been restricted. It has never been presented as *THE* PHP standard, but just as one with the merit to exists.
ReplyDelete2. Nobody is forced to adopt PSR-0. The inclusion into the core would help all of those who follow that standard with no obligation. The same has been true when introducing autoloading, there is still many projects using require_once() and there is nothing wrong with that.
After all, there is still many projects which doesn't use SPL at all, everybody remains free to choose what they want. The default implementation of spl_autoload() exists in core and nobody has been forced to use it.
One note however, I think it is bad to name such an autoloader class without a reference to PSR-0.
"SplClassLoader" might be an abstract class/interface or whatever, it is more fair to name a PSR-0 loader class as SplPsr0Loader for example.
3. Your arguments regarding case sensitivity are quite meaningless. The PSR-0 standard doesn't impose any magic regarding class name case and it shouldn't. By not introducing magic, if follows a strict approach: case are preserved as-is.
How can a strict approach be considered inconsistent?
Edge cases have nothing to do with the standard itself and also exists with spl_autoload():
- create class Foo in Foo.php
- php> spl_autoload_register(); new Foo;
That would work under Windows but not *nix.
Remember that class name lowercasing is only done *inside* spl_autoload(), registered spl autoload function will always be called with the case unchanged.
4. Stop thinking this is for framework interests! It benefits everyone who already use PSR-0 as part of their coding standards. And that is in no way related to the use of a framework or not. It has been made by a group named "Framework Interop Group" but that's really the only framework related thing.
Please, stop reacting as if we are about to impose something to every PHP developers, that is simply NOT the case. You mention several times "the language" erroneously, that would just be an available feature and there is no point arging it shouldn't be introduced just because you don't want to use it.
--
Patrick
@Patrick
ReplyDeleteHaving an open mailing list is not an RFC process. It's also not getting input from other developers outside the interests. The "standard" was never mentioned on any php.net list until 2011 (2 years after adoption). So how can you have solicited input to make it a standard if it was never even promoted on official lists? I'm making the point that this isn't actually a standard (in the IT sense of the word), but a convention that some people agreed upon.
With respect to the fact that it's optional, I think that's one reason it doesn't belong in the *language*. It's completely implementable with very little performance difference in PHP. So why does it need to be in core? What advantages are there?
The argument about case sensitivity is a real one. The language should not force a style convention. Right now, there's nothing in PHP that forces any particular *code* style conventions. Sure, spl_autoload enforces a filename convention. But you can still use any code style you want (new foo vs new Foo). I'd argue that even the filename convention is bad and doesn't belong, but it's there already.
It is about framework interests. You want to standardize the convention you use. Great. But don't think it's about interoperability or anything else like that. spl_autoload_register provides interoperability (in that each library is free to define how it wants to implement the autoloader on its own terms).
I actually do use a PSR-0 compliant autoloader in most of my projects (some on github). It's not that I like or dislike the convention. But liking and using something is very different from belonging in the core.
Remember, PHP is a language. It's not a framework. It's not supposed to take sides in conventions or standards or best practices. It's supposed to enable all of those things to happen.
Now, with that said. Would you want to implement 10 different autoloaders in the core? One for PEAR naming conventions. One for PSR-0 case insensitive. One for PSR-1. One for Wordpress (assuming they have one). One that takes advantage of features in PHP 7.2? No, that's ridiculous.
That's why it's very important to keep framework and convention interests *out* of the language. They don't belong there.
Anthony
I agree with you Anthony and you raised a lot of valid concerns. PSR-0 doesn't fit my idea of a modular framework and mapping namespace to the file system is in my opinion a false good idea. I'll stick to my personal index based autoloader hoping that PSR-0 doesn't make it to the core.
ReplyDelete@ircmaxell,
ReplyDelete"The "standard" was never mentioned on any php.net list until 2011 (2 years after adoption)."
Really? Wasn't the discussion set up as a php.net ML, and then got kicked off? My memory is a bit foggy there though, as it was several years ago.
"I'm making the point that this isn't actually a standard (in the IT sense of the word), but a convention that some people agreed upon."
That is what a standard is. A convention that some people agreed upon. You could maybe argue though that its a defacto standard rather than a technical standard.
"argument about case sensitivity is a real one"
Anybody worrying about interop will treat filenames/classnames as cases sensitive, even though the language does not. This is a language/filesystem issue. It is not something the loader should solve (can it?).
"Remember, PHP is a language. It's not a framework. It's not supposed to take sides in conventions or standards or best practices."
We're talking about SPL, which can (and does) take sides in conventions/standards/best practices, even though it is included in PHP core.
"Now, with that said. Would you want to implement 10 different autoloaders in the core? One for PEAR naming conventions. One for PSR-0 case insensitive. One for PSR-1."
straw man. PEAR is PSR-0 compliant. It would also be stupid to break backwards compatibility with future iterations. So a PSR-x compliant autoloader also be PSR-0 compliant. There's no need to have a different class for subsequent versions.
I'm not sure if the autoloader should be included in core either (yet). The standard basically covers how to translate a namespace+classname to a filename. An implementation of that standard, however, should do more than a glorified string replacement. And that's where things begin to get a bit hazy. Do we want an implementation that is "feature complete", or do we want one that is bare-bones?
Personally, I wish they had made autoloading part of the namespace importing, and that it also included handling functions and constants, but that's probably asking too much...
@David:
ReplyDeleteRe: discussion. I didn't see it, and I tried searching and there was no mention of anything related to autoloading with that respect that I could find. I could be wrong, but I would expect to see at least even a mention of the approved name (PSR-0) which there was not...
A standard is not "just" a convention though. A standard implies a whole level of formality above convention. That's why we have call them defacto-standards (because they are agreed upon without the formality). And that's the problem that I'm pointing out here. The common steps and formality that go into normal standards either did not happen at all, or are not documented as part of the standard. So it's really just a convention that has support...
With respect to case sensitivity, that is a problem the autoloader can solve. The current spl one implemented handles that by forcing the file names to lowercase. I'm not saying that PSR-0 should do that, but it should make some mention at least of the problem or limitation if not measures against it.
With respect to SPL, your point is invalid. Where does SPL make a single side in code level conventions/standards/best-practices? The only possible thing you could say is spl_autoload with the mapping to the filesystem, but that's a file convention, not a code level one. So no, there are no coding conventions in SPL.
The versions argument is NOT a straw-man. First off, future versions would need to either break backwards compatibility with either API or function of the loader. It's not possible to maintain both, since if the interface and behavior are the same, the class is the same. That further complicates things due to the Open-Closed principle. Even if you could build it completely without mucking up the interface, you're now complicating things since the same class name behaves differently in different versions of PHP. Which would cause significant pain down the road.
So the only sane thing would be to have multiple versions of the class with separation of naming. Then "legacy" implementations can be made to retrofit for older versions. Why? Because PHP has a long release cycle. And an even longer adoption cycle. 5.3 is JUST now starting to gain mass adoption. So we're talking years (possibly 3 or 4) between when a new standard is implemented and when it's available to most hosts. So you're effectively locking in for years and years to the current implementation.
Additionally, what happens for people who want to use the PHPAB style autoloader? Should they get support in core? Why not? In fact, I'd argue that implementation has more to gain in the core since you're saving iteration and string functions back down to C. So now we have 3 different autoload implementations in core. And what happens when 3 years down the road another standard emerges due to unforseen limitations in the current one? Is that really such a far fetched idea? Things evolve, face it.
The language should *support* all standards and sane implementations. But it should not implement any of them directly. That's the job for libraries and extensions. Otherwise why not implement a full framework in the core? Even the ROR guys haven't gotten that far...
I think PSR-0 is a good thing. As Patrick said.
ReplyDelete"Issue #1 - It is inconsistent"
I really don't see how it is. I think your example is poor. File systems are inconsistant, not the class loader itself. Give me an example of a loader that would work with the example you gave.
"Issue #2 - It is not a standard"
I think it matches the SPL library well (SPL is a collection of interfaces and classes that are meant to solve standard problems). I read standard here as common problems. When did any of the API's for the SPL go into RFCs?
"Issue #3 - There's nothing for the core to gain"
Well that depends on if you use it. Just because you don't use something does that mean others shouldn't benifit from it?
I can't quite see what the fuss is. Maybe you can explain that to me. No one is enforcing a loader on you. This isn't a language change, this is an addition of a loader class.
With all that said I'm quite happy using the class loader as a PHP file. I am unsure of the benifit of adding it into PHP. But thats as far as my concerns go.
The original mailing list was on php.net. But the group decided to move elsewhere to avoid/lock out discussion of any previously made decisions. See Rasmus http://news.php.net/php.standards/start/18 and Greg. And the second php-standards mailing list was read-only for the populace till three weeks ago http://groups.google.com/group/php-standards/browse_thread/thread/6d6dce5264a2f90/5991355f296b5440?lnk=gst&q=pending#5991355f296b5440
ReplyDeleteThe reason for SplClassLoader being pushed into core is not performance. It's very blatantly to cement PSR-0 per endorsement as language feature. The framework uptake isn't as strong as the group makes it out to be. (See FuelPHP or Fat-Free, or any of the other *newer* frameworks.)
PSR-0 was strictly designed with *legacy* frameworks in mind. That's why the conflict with retaining the filename casing and ambigious mappings never even occured to them. (It wasn't a real problem for PEAR1, because it was only the first `require` that needed the magic constant values for locating includes. All class instantiations were unaffected.)
The compatibility questions notwithstanding, it's most certainly not the fastest autoloader anyway. PECL Automap always was (and language compliant at that!), and any userland mapper would certainly outperform SplClassLoader. (PECL Automap doesn't work with PHP 5.3 anymore. And seemingly none of the bigger frameworks investigated updating it. So the performance argument really seems to be just a decoy.)
OTOH I wouldn't mind it going into core if it was at least a little tested (so PHP 5.5 rather). There's so many deprecated and unused features already that it wouldn't matter. But it's most certainly too early now. It's not widely used yet, simply because PHP 5.3 just reached 15% server saturation (http://w3techs.com/technologies/details/pl-php/5/all). So real-world namespace usage is still slim. (In other news, I just found out my provider does have 5.3, but kept it a secret. Muhuwaha, path traversal.)
This comment has been removed by the author.
ReplyDelete@Patrick Participation to that group was restricted for quite a while. I believe it is completely open now.
ReplyDelete@David The mailing list was a closed list. It was kicked off because the public could not participate.
I've written a blog post which criticize the proposed class from an OOP design perspective.
ReplyDeletehttp://blog.mohiva.com/2011/11/discussion-about-psr-0-autolaoder-in.html
"It is not a standard"
ReplyDeleteits clearly a defacto standard. did i agree with the setup of the original list that came up with PSR-0? no! not because it was a closed list, but because it gave the pretense of representing the entire PHP community (mostly through the name choice).
however technically it doesn't matter how this "standard" came about "politically". its here now and its significant based on the adoption by some of the biggest PHP user bases. PSR-0 had more relevance to PHP core than 85% (wild unsubstantiated guess) array functions in core.
@Lukas: There's a name for what you're calling a "defacto standard". It's called a convention. And just because a **very** small minority of code that exists is using it means that it's not really as critical as people are making it out to be.
ReplyDeleteWith respect to the array functions, that's a bad example as the majority of them are actually quite useful for one of two reasons: either they are inefficient to implement in userland (sorting), or they provide a simple means to perform an action. I've used almost every single array function in live code. I'd also venture to guess that anyone who's done any significant amount of dev in PHP has as well.
Now, if you would have brought up the string functions I would agree. Strpbrk? convert_cyr_string? money_format? nl_langinfo? Etc.
However, I would argue that saying that is a strawman argument and is really just a textbook case of Broken Window Theory (http://en.wikipedia.org/wiki/Broken_windows_theory). If you ever want it to get better, you need to draw a line somewhere.
And considering this RFC is really vague and is really in flux with nobody agreeing on anything except that they want a PSR-0 autoloader in core, I think this is a perfect case for a line. ..
Ugh. Why is the php team always trying to bloat core with stuff like this, when something like process control is kept external?
ReplyDeleteHey, I got the same feeling as the guy above. We have so much important stuff to work on. I can not agree we should even discuss such things as PSR-0 as this is "a one guy wish" and nothing more compared to a number of php developers out there.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThe point the author is making, I believe, is that irregardless of the merits of the actual technology, the process seems to be flawed.
ReplyDeleteI don't agree with all points made here, but #2 is pretty clear: more information and clarification is needed in the proposal, as well as how a proposal can go from "idea" to "implemented in core".
Though, some aspects of the reference implementation do concern me as they have the possibility of breaking existing code when an alternative implementation could keep things working.
RFC's have a long standing tradition on the 'Net, and they work on many levels from open discussion to clear, discoverable and consistent documentation. PSR's should have the same level of clarity and standardization as any Internet RFC.
Just FINDING the PSR is difficult, and the only source I can come up with is the Framework Interop Group github account?
Shouldn't the PHP Standards group at least have a website where official accepted PSR's are posted permanently, before starting to add things to the core?
I could be confused, and if so, I apologize -- I just stumbled on PSR-0 while searching for something else.