<?php | |
/* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* | |
* This software consists of voluntary contributions made by many individuals | |
* and is licensed under the MIT license. For more information, see | |
* <http://www.doctrine-project.org>. | |
*/ | |
/** | |
* SplClassLoader implementation that implements the technical interoperability | |
* standards for PHP 5.3 namespaces and class names. | |
* | |
* http://groups.google.com/group/php-standards/web/psr-0-final-proposal?pli=1 | |
* | |
* // Example which loads classes for the Doctrine Common package in the | |
* // Doctrine\Common namespace. | |
* $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine'); | |
* $classLoader->register(); | |
* | |
* @license http://www.opensource.org/licenses/mit-license.html MIT License | |
* @author Jonathan H. Wage <jonwage@gmail.com> | |
* @author Roman S. Borschel <roman@code-factory.org> | |
* @author Matthew Weier O'Phinney <matthew@zend.com> | |
* @author Kris Wallsmith <kris.wallsmith@gmail.com> | |
* @author Fabien Potencier <fabien.potencier@symfony-project.org> | |
*/ | |
class SplClassLoader | |
{ | |
private $_fileExtension = '.php'; | |
private $_namespace; | |
private $_includePath; | |
private $_namespaceSeparator = '\\'; | |
/** | |
* Creates a new <tt>SplClassLoader</tt> that loads classes of the | |
* specified namespace. | |
* | |
* @param string $ns The namespace to use. | |
*/ | |
public function __construct($ns = null, $includePath = null) | |
{ | |
$this->_namespace = $ns; | |
$this->_includePath = $includePath; | |
} | |
/** | |
* Sets the namespace separator used by classes in the namespace of this class loader. | |
* | |
* @param string $sep The separator to use. | |
*/ | |
public function setNamespaceSeparator($sep) | |
{ | |
$this->_namespaceSeparator = $sep; | |
} | |
/** | |
* Gets the namespace seperator used by classes in the namespace of this class loader. | |
* | |
* @return void | |
*/ | |
public function getNamespaceSeparator() | |
{ | |
return $this->_namespaceSeparator; | |
} | |
/** | |
* Sets the base include path for all class files in the namespace of this class loader. | |
* | |
* @param string $includePath | |
*/ | |
public function setIncludePath($includePath) | |
{ | |
$this->_includePath = $includePath; | |
} | |
/** | |
* Gets the base include path for all class files in the namespace of this class loader. | |
* | |
* @return string $includePath | |
*/ | |
public function getIncludePath() | |
{ | |
return $this->_includePath; | |
} | |
/** | |
* Sets the file extension of class files in the namespace of this class loader. | |
* | |
* @param string $fileExtension | |
*/ | |
public function setFileExtension($fileExtension) | |
{ | |
$this->_fileExtension = $fileExtension; | |
} | |
/** | |
* Gets the file extension of class files in the namespace of this class loader. | |
* | |
* @return string $fileExtension | |
*/ | |
public function getFileExtension() | |
{ | |
return $this->_fileExtension; | |
} | |
/** | |
* Installs this class loader on the SPL autoload stack. | |
*/ | |
public function register() | |
{ | |
spl_autoload_register(array($this, 'loadClass')); | |
} | |
/** | |
* Uninstalls this class loader from the SPL autoloader stack. | |
*/ | |
public function unregister() | |
{ | |
spl_autoload_unregister(array($this, 'loadClass')); | |
} | |
/** | |
* Loads the given class or interface. | |
* | |
* @param string $className The name of the class to load. | |
* @return void | |
*/ | |
public function loadClass($className) | |
{ | |
if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) { | |
$fileName = ''; | |
$namespace = ''; | |
if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) { | |
$namespace = substr($className, 0, $lastNsPos); | |
$className = substr($className, $lastNsPos + 1); | |
$fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; | |
} | |
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; | |
require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; | |
} | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
Maybe it shouldn't use |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
None of the links to the PSR-0 proposal work. Here is a working one on google cache: http://webcache.googleusercontent.com/search?q=cache:XOHGigFVti8J:groups.google.com/group/php-standards/web/psr-0-final-proposal+https://groups.google.com/group/php-standards/web/psr-0-final-proposal&cd=1&hl=en&ct=clnk&gl=pl&lr=lang_pl|lang_en |
This comment has been minimized.
This comment has been minimized.
Wow, someone had better back it up before it's gone forever and there's no reference.Jonah
…-------- Original Message --------
Subject: Re: gist gist: 221634
From: Artur Bodera
reply@reply.github.com
Date: Tue, September 20, 2011 7:59 am
To: Jonah Dahlquist jonah@nucleussystems.com
None of the links to the PSR-0 proposal work.
## Here is a working one on google cache: http://webcache.googleusercontent.com/search?q=cache:XOHGigFVti8J:groups.google.com/group/php-standards/web/psr-0-final-proposal+https://groups.google.com/group/php-standards/web/psr-0-final-proposal&cd=1&hl=en&ct=clnk&gl=pl&lr=lang_pl|lang_en
Reply to this email directly or view it on GitHub:https://gist.github.com/221634
|
This comment has been minimized.
This comment has been minimized.
How ridiculous. I put it on my blog in case the cache disappears. http://blog.montmere.com/2011/09/21/psr-0-final-proposal/ |
This comment has been minimized.
This comment has been minimized.
Awesome, bookmarked.Jonah
…-------- Original Message --------
Subject: Re: gist gist: 221634
From: "Stephen J. Fuhry"
reply@reply.github.com
Date: Wed, September 21, 2011 1:05 pm
To: Jonah Dahlquist jonah@nucleussystems.com
## How ridiculous. I put it on my blog in case the cache disappears. http://blog.montmere.com/2011/09/21/psr-0-final-proposal/
Reply to this email directly or view it on GitHub:https://gist.github.com/221634
|
This comment has been minimized.
This comment has been minimized.
I've created a gist (md) version of the proposal: https://gist.github.com/1234504 |
This comment has been minimized.
This comment has been minimized.
@jonahbron @Thinkscape @till @lisachenko @fuhrysteve Google Groups does not support pages. Cheers, |
This comment has been minimized.
This comment has been minimized.
@till Obviously for the reason that |
This comment has been minimized.
This comment has been minimized.
@LessThanThree So? You want an E_COMPILE_ERROR from class_exists() calls? I would like to see lisachenko's comment realized. Or maybe another parameter if or not to throw exceptions and errors. |
This comment has been minimized.
This comment has been minimized.
@bxt I usually want to halt the execution whenever a non existent file is imported, that's why I'd favor |
This comment has been minimized.
This comment has been minimized.
@LessThanThree but you might want to pass to downstram autoloaders, and if a class is not found execution is stopped anyway. Maybe the best solution would be checking if the file exists and then |
This comment has been minimized.
This comment has been minimized.
Here is my version for PSR-0 proposal https://gist.github.com/1335891. It checks existence of the file and have two more features: relative paths and multiple include paths for single namespace. So you can configure loader like this:
|
This comment has been minimized.
This comment has been minimized.
Is anyone likely to actually need to change the namespace separator at runtime using those getters and setters? Perhaps I'm failing to understand what use-case that functionality is intended for, but wouldn't it be better to define that value as a constant instead? |
This comment has been minimized.
This comment has been minimized.
@henry-smith Agree with you. Namespace separator is defined as a constant and definitely won't be changed. |
This comment has been minimized.
This comment has been minimized.
@henry-smith and @lisachenko I think you guys are missing the point of the namespace separator. It's not there because you're going to change the namespace separator at runtime. That _would_ be silly. Instead, it exists to support interoperability between different class naming conventions across vendor libraries in the same project. For example, let's say you use a class from the original Zend Framework in your project. The ZF1 class naming convention uses underscores and looks like $myLibLoader = new SplClassLoader('mylib', '/path/to/mylib/src');
$myLibLoader->register();
$zendLoader = new SplClassLoader('Zend', '/path/to/zend/lib');
$zendLoader->setNamespaceSeparator('_');
$zendLoader->register(); Obviously, if you only utilize one namespace in your project and don't reference outside vendor libraries you'll never have need of this functionality. As far as using
|
This comment has been minimized.
This comment has been minimized.
Ah, nice clarification. I understand now, thanks. The docblock for setNamespaceSeparator() does kind of imply this too:
The meaning of that would be absolutely clear to anyone who had that need as well. Kind of presumptuous of me to try to second guess a design decision just because I didn't understand it. Sorry about that! |
This comment has been minimized.
This comment has been minimized.
@lisachenko (comment on July 12, 2011), why do you think that loadClass() must return boolean result? PHP checks after each autoloader if class exists and if it's true it stop autoloaders queue. See http://www.php.net/manual/ru/function.spl-autoload-register.php#96952 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Setters could return $this for method chaining. Powerful in 5.4 (new SplClassLoader())->setIncludePath(realpath(dirname(__FILE__) . '/lib'))
->register(); |
This comment has been minimized.
This comment has been minimized.
I was trying to load the Slim Framework like this: $classLoader = new SplClassLoader('Slim', 'libs/Slim');
$classLoader->setNamespaceSeparator('_');
$classLoader->register(); But I wasn't able to, I found the problem was the following in Line 123: $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator)) The problem is that the statement looks like |
This comment has been minimized.
This comment has been minimized.
If this class is to insist on require() instead of include & return false, and it's being held up as the gold standard by the authors of PSR, then surely for consistency they should deprecate the class_exists() function? As has been noted by several people above, the autoloader is not called only when a class is needed; it is also called whenever a class' existence needs to be checked, particularly in frameworks and apps that use a plugin architecture. Autoloaders which ignore this are broken. |
This comment has been minimized.
This comment has been minimized.
I must agree with @parsingphase. A stacked autoloader implementation with require() must only use require if it first checks with either file_exists() or is_readable(). |
This comment has been minimized.
This comment has been minimized.
you should use strtr (for a char replace) vs str_replace (more faster) ... |
This comment has been minimized.
This comment has been minimized.
SRP principle : you have forget a resolveFileName($class) function, should not be defined in loadClass function ... |
This comment has been minimized.
This comment has been minimized.
Wouldn't be better if the path matching with the class name was previously converted to lowercase? Example: class: |
This comment has been minimized.
This comment has been minimized.
Why does the constructor accept NULL value for both parameters? That makes no sense in my opinion. |
This comment has been minimized.
This comment has been minimized.
This example doesn't follow PSR-2 coding style. I think PSR should refer to examples which follow PSR. There is at least one issue - private members prefixed with "_". |
This comment has been minimized.
This comment has been minimized.
Isn't it a little strange use a construction like "if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator)))[...]", with the false statement first? Looks like a little causative (like master yoda talks) |
This comment has been minimized.
This comment has been minimized.
How about having a static class that do all the work for a generic autoloading public static function autoRegister($ns = null, $includePath = null){
$instance = new static($ns, $includePath);
$instance->register();
} |
This comment has been minimized.
This comment has been minimized.
The comment of @parsingphase is so true!
|
This comment has been minimized.
This comment has been minimized.
Just in case you need a lightweight solution to autoload PSR-0 and Zend like libs, take a look at this gist. It's extreme, it's not following PSR-1 / PSR-2 coding standards at all, but it's short, fun and effective : <?php
set_include_path(get_include_path().PATH_SEPARATOR.__DIR__);//optional
spl_autoload_register(function($c){
@include preg_replace('#\\\|_(?!.*\\\)#','/',$c).'.php';
}); |
This comment has been minimized.
This comment has been minimized.
Thanks for the useful autoloader! |
This comment has been minimized.
This comment has been minimized.
This class should be updated to match the the PSR-2 standard |
This comment has been minimized.
This comment has been minimized.
Very useful~ |
This comment has been minimized.
This comment has been minimized.
This is the way I do it. It only
|
This comment has been minimized.
This comment has been minimized.
Current implementation implicitly shows that there is only one include path possible for one Vendor Name But let`s imagine I have the following structure of the code There is no one rule from PSR-0 has conflict with this case:
|
This comment has been minimized.
This comment has been minimized.
You cannot have the same namespace in two folders, like your Vendor1. You might be lucky and have Subnamespaces below that Namespace1, and can then use this loader. Otherwise, you'd have to solve the question of "how do you know where the file for a class is", and if the answer is "I start looking in folder1, and if nothing is found, continue with folder2", that might work, but is is not really PSR-0 compliant. And it isn't feasible as well. What if the same class exists in both folders? |
This comment has been minimized.
This comment has been minimized.
What do you think is it make sense to add this rule item into PSR-0 standards? |
This comment has been minimized.
This comment has been minimized.
I think "include" is more logical, after all the method class loader utilises to load a class should be encapsulated. No one needs to know about that, so using "file_exists" is the best. If the class is not found with your class load the php will keep searching until it reaches the last class loader, you don't need to worry about boolean return either. A fatal error will be generated if PHP not found the class anyway. Don't forget that some libraries use their own class loaders and using "require" will break them. |
This comment has been minimized.
This comment has been minimized.
pls add a licence ( LGPL / MIT / BSD / GPL / AGPL ) |
This comment has been minimized.
This comment has been minimized.
Am I missing something here (I'm a namespace noob)? Using a namespaced class such as Zend\XmlRpc\Server.php (use Zend\XmlRpc) and stepping through the code, the function :
always returns false for namespaced classes because the $className parameter is the bare
If I modify the calling code to use the namespaced class like this:
... and use this later ...
then it returns true as expected. The class file is successfully loaded in any case as the file path is correctly setup so you don't actually see much happen even if the function does return false but I am fairly certain it should return true. |
This comment has been minimized.
This comment has been minimized.
There was a problem with constants I'd defined. My BASE_PATH CONST was defined like this define('BASE_PATH', dirname(realpath(__FILE__)) . '/'); So when I instantiated your class like this $classLoader = new SplClassLoader('App\Controllers\Content', BASE_PATH); The trailing Slash from my BASE_PATH Const was the causefor an error. public function __construct($ns = null, $includePath = null) { $this->_namespace = $ns; $this->_includePath = rtrim($includePath, '/'); } Perhaps something for the next Version.....no one needs trailing slashes :) |
This comment has been minimized.
This comment has been minimized.
As ClemensSahs mentioned I would also like to know the license for this code. |
This comment has been minimized.
This comment has been minimized.
Please remove the http://groups.google.com/group/php-standards/web/final-proposal link in the file, it leads to a |
This comment has been minimized.
This comment has been minimized.
Zeokat very usefull piece of code. I need to know the license because i thinking into using it. |
This comment has been minimized.
This comment has been minimized.
Hi All, Why declared methods setIncludePath / getIncludePath and not declared methods getNamespace and setNamespace in this SplClassLoader ?? Regards |
This comment has been minimized.
This comment has been minimized.
Download file of this gist don't have white line in the end file. See PSR2 |
This comment has been minimized.
This comment has been minimized.
This link Is a fork to this file with the next PHPDoc fixes:
|
This comment has been minimized.
This comment has been minimized.
I think, there is a problem with this implementation or the PSR-0 itself. When - theoretically - using classnames that begin or end with and underscore "", e.g. \Vendor\Namespace_Class_Extension.php This would end up in something like this: There is no omission or MUST NOT for leading or trailing underscores in the definition of classnames. To avoid this, just replace the line: <?php
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; with <?php
$fileName .= preg_replace("#([a-z0-9]+)_([a-z0-9]+)#i", "$1" . DIRECTORY_SEPARATOR . "$2", $className) . $this->_fileExtension; and the example above will end up in:
|
This comment has been minimized.
This comment has been minimized.
Maybe useful: Btw, consider using PSR4 autoloader: |
This comment has been minimized.
This comment has been minimized.
Here is the file loading solution I use within my autoloader: include $filename; Why I use this: file_exists(fileName){ From a application run time perspective its like loading the file twice !!! In addition require will kill your app if it fails where include only throws a warning. Testing if the class or interface exists after an include will give you options to try something else before YOU gracefully exit your application. Hope this helps |
This comment has been minimized.
This comment has been minimized.
Got it. |
This comment has been minimized.
This comment has been minimized.
Maybe replace 'require' with 'require_once' in loadClass(...) method ? |
This comment has been minimized.
This comment has been minimized.
Hi guys, I have trouble. If I require the classes manually everything works as expected (any errors are displayed). Any suggestions? |
This comment has been minimized.
This comment has been minimized.
get class in to on? |
This comment has been minimized.
This comment has been minimized.
SplClassLoader line 133 is throwing error. File not found. But the file is present in another folder, how to fix this |
This comment has been minimized.
This comment has been minimized.
It is just a test https://gist.github.com/Romanzo/2cd7b5cc382f5f419670 |
This comment has been minimized.
This comment has been minimized.
Hello there people! New important info forgotten here.. The method loadClass on line 141 must return a boolean value! Recomended:
This is imperative! PHP SPL autoload function suports bubbling effect.. You can register as many autoload functions as necessary, so, you must return a boolean value to indicate if the function loaded the resource or not. If it returns The second parameter in every Also, it's recommended to use See ya! |
This comment has been minimized.
This comment has been minimized.
I am trying this code from last 5 hours and it dint work. |
This comment has been minimized.
This comment has been minimized.
Can someone remove the spam comments from 2017 (since first-reviews' comment)? I don't see any possibility to flag them from my side.. |
This comment has been minimized.
The link in the header comment is broken, the document is now located here:
http://groups.google.com/group/php-standards/web/psr-0-final-proposal?pli=1