-
-
Save jwage/221634 to your computer and use it in GitHub Desktop.
<?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 <[email protected]> | |
* @author Roman S. Borschel <[email protected]> | |
* @author Matthew Weier O'Phinney <[email protected]> | |
* @author Kris Wallsmith <[email protected]> | |
* @author Fabien Potencier <[email protected]> | |
*/ | |
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; | |
} | |
} | |
} |
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:
Vendor/Namespace//Class/Extension/.php
and will definitely fail to load.
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:
Vendor/Namespace/_Class/Extension_.php
Maybe useful:
https://github.com/keradus/SplClassLoader - taken from PSR and little fixed like docs etc.
If need anything to change just PR.
Btw, consider using PSR4 autoloader:
https://github.com/keradus/Psr4Autoloader
Here is the file loading solution I use within my autoloader:
REM** $class can be a Class OR an Interface
include $filename;
// Check to see if the include declared the class
if(!class_exists( $class, FALSE )) {
// Check to see if the include declared the interface
if(!interface_exists( $class, FALSE )){
// We do not have the class nor interface : file did not load or did not exist
// Do something : Log error; check other file resources or die gracefully.
}
}
Why I use this:
Loading files is normally the slowest part of any php application. Using file_exists(), even though it does not load the file still takes 'almost' as much time as loading the file itself (assuming a small file which class files tend to be >10Kb). So if you use:
file_exists(fileName){
require 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
Got it.
Maybe replace 'require' with 'require_once' in loadClass(...) method ?
http://php.net/manual/en/function.require-once.php
Hi guys, I have trouble.
Using SplClassLoader loosing displaying of parse errors and it is really pain the ass to debug the code manually. I can only catch then with register_shutdown_function(). I have set error_reporting to E_ALL, I did almost everything to display them and nothing.
If I require the classes manually everything works as expected (any errors are displayed). Any suggestions?
get class in to on?
SplClassLoader line 133 is throwing error. File not found. But the file is present in another folder, how to fix this
It is just a test https://gist.github.com/Romanzo/2cd7b5cc382f5f419670
Hello there people! New important info forgotten here..
The method loadClass on line 141 must return a boolean value! Recomended:
return class_exists($className, false) || trait_exists($className, false) || interface_exists($className, false);
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 true
, the SPL stops casting autoload functions.. if it returns false
it keeps goin on the rest of the functions registered through spl_autoload_register.
The second parameter in every *_exists
methods refer to autoloading and it must be false
inside the autoload function scope to avoid infinite loop (the autoload function casting itself). If you try to load an interface, class_exists
will drop false
, because it's not a class, but interface_exists
will drop true
, then the autoload stops trying to load that resource.
Also, it's recommended to use include_once
than any of other options. For instance, if you try to load My\Personal\Class\Name
and My_Personal_Class_Name
as the code is it will drop a fatal error trying to duplicate the resource (class, trait or interface). The fix proposed here will solve this problem.
See ya!
I am trying this code from last 5 hours and it dint work.
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 link
https://gist.github.com/r2pq/aebc8131955ee819086f
Is a fork to this file with the next PHPDoc fixes: