rfc:splclassloader
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:splclassloader [2011/11/07 18:32] – [Request for Comments: SplClassLoader] Added link to vote page rdohms | rfc:splclassloader [2012/06/29 06:52] – laruence | ||
---|---|---|---|
Line 29: | Line 29: | ||
* Alphabetic characters in vendor names, namespaces, and class names may be of any combination of lower case and upper case. | * Alphabetic characters in vendor names, namespaces, and class names may be of any combination of lower case and upper case. | ||
- | ===== Usage Examples ===== | + | ===== Extended Rules for Proposal ===== |
+ | |||
+ | Together with PSR-0 rules, for SplClassLoader we would also include a few valid rules that must be implemented, | ||
+ | |||
+ | * Allow a namespace to be mapped through multiple paths. | ||
+ | * Make SplClassLoader silently fails if class is not found. This one is useful when using multiple instances of SplClassLoader in a single script. | ||
+ | * Allow SplClassLoader to lookup in include_path. This is useful for projects that define their own on include_path, | ||
+ | |||
+ | ===== Flexibility of a Rule ===== | ||
+ | |||
+ | Even though PSR-0 is strict, PHP cannot force php extension. Ideally, the file extension is customizable, | ||
+ | |||
+ | ===== Initial missing support ===== | ||
+ | |||
+ | PHP does not provide a single approach for any OO based autoloader, so initially a new interface is required, for anyone interested to implement their own Autoloader. From now on, let's name it as SplAutoloader. | ||
+ | The purpose of this interface is to bring the minimum contract that any interested to autoload their resources should follow. | ||
+ | Here is the proposed implementation: | ||
+ | |||
+ | <code php> | ||
+ | /** | ||
+ | * SplAutoloader defines the contract that any OO based autoloader must follow. | ||
+ | * | ||
+ | * @author Guilherme Blanco < | ||
+ | */ | ||
+ | interface SplAutoloader | ||
+ | { | ||
+ | /** | ||
+ | * Defines autoloader to work silently if resource is not found. | ||
+ | * | ||
+ | * @const | ||
+ | */ | ||
+ | const MODE_SILENT = 0; | ||
+ | |||
+ | /** | ||
+ | * Defines autoloader to work normally (requiring an un-existent resource). | ||
+ | * | ||
+ | * @const | ||
+ | */ | ||
+ | const MODE_NORMAL = 1; | ||
+ | |||
+ | /** | ||
+ | * Defines autoloader to work in debug mode, loading file and validating requested resource. | ||
+ | * | ||
+ | * @const | ||
+ | */ | ||
+ | const MODE_DEBUG = 2; | ||
+ | |||
+ | /** | ||
+ | * Define the autoloader work mode. | ||
+ | * | ||
+ | * @param integer $mode Autoloader work mode. | ||
+ | */ | ||
+ | public function setMode($mode); | ||
+ | |||
+ | /** | ||
+ | * Add a new resource lookup path. | ||
+ | * | ||
+ | * @param string $resourceName Resource name, namespace or prefix. | ||
+ | * @param mixed $resourcePath Resource single path or multiple paths (array). | ||
+ | */ | ||
+ | public function add($resourceName, | ||
+ | |||
+ | /** | ||
+ | * Load a resource through provided resource name. | ||
+ | * | ||
+ | * @param string $resourceName Resource name. | ||
+ | */ | ||
+ | public function load($resourceName); | ||
+ | |||
+ | /** | ||
+ | * Register this as an autoloader instance. | ||
+ | * | ||
+ | * @param boolean Whether to prepend the autoloader or not in autoloader' | ||
+ | */ | ||
+ | public function register($prepend = false); | ||
+ | |||
+ | /** | ||
+ | * Unregister this autoloader instance. | ||
+ | * | ||
+ | */ | ||
+ | public function unregister(); | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Examples | ||
The standards we set here should be the lowest common denominator for painless autoloader interoperability. You can test that you are following these standards by utilizing this sample SplClassLoader implementation which is able to load PHP 5.3 classes. | The standards we set here should be the lowest common denominator for painless autoloader interoperability. You can test that you are following these standards by utilizing this sample SplClassLoader implementation which is able to load PHP 5.3 classes. | ||
Line 46: | Line 130: | ||
* / | * / | ||
- | ===== Example implementation ===== | + | ===== Examples of usage ===== |
+ | |||
+ | Autoloading Doctrine 2: | ||
+ | |||
+ | <code php> | ||
+ | $classLoader = new \SplClassLoader(); | ||
+ | $classLoader-> | ||
+ | '/ | ||
+ | )); | ||
+ | $classLoader-> | ||
+ | </ | ||
+ | |||
+ | Autoloading PEAR1: | ||
+ | |||
+ | <code php> | ||
+ | $classLoader = new \SplClassLoader(); | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | </ | ||
+ | |||
+ | Autoloading in debug mode: | ||
+ | |||
+ | <code php> | ||
+ | $classLoader = new \SplClassLoader(); | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | $classLoader-> | ||
+ | </ | ||
+ | |||
+ | ===== Example | ||
Below is an example function to simply demonstrate how the above proposed standards are autoloaded. | Below is an example function to simply demonstrate how the above proposed standards are autoloaded. | ||
Line 56: | Line 172: | ||
$fileName | $fileName | ||
$namespace = ''; | $namespace = ''; | ||
+ | | ||
if ($lastNsPos = strripos($className, | if ($lastNsPos = strripos($className, | ||
$namespace = substr($className, | $namespace = substr($className, | ||
Line 61: | Line 178: | ||
$fileName | $fileName | ||
} | } | ||
+ | | ||
$fileName .= str_replace(' | $fileName .= str_replace(' | ||
Line 70: | Line 188: | ||
The following class is a sample SplClassLoader implementation that can load your classes if you follow the autoloader interoperability standards proposed above. It is the current recommended way to load PHP 5.3 classes that follow these standards. | The following class is a sample SplClassLoader implementation that can load your classes if you follow the autoloader interoperability standards proposed above. It is the current recommended way to load PHP 5.3 classes that follow these standards. | ||
- | |||
- | > NOTE: This implementation is not the proposed final. It requires two updates: | ||
- | > * Multiple paths per namespace | ||
- | > * Silent mode | ||
<code php> | <code php> | ||
- | <?php | ||
- | |||
/** | /** | ||
* SplClassLoader implementation that implements the technical interoperability | * SplClassLoader implementation that implements the technical interoperability | ||
* standards for PHP 5.3 namespaces and class names. | * standards for PHP 5.3 namespaces and class names. | ||
* | * | ||
- | | + | |
+ | * | ||
+ | * Example usage: | ||
+ | * | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
* | * | ||
- | * // Example which loads classes for the Doctrine Common package | + | |
- | | + | |
- | * $classLoader = new SplClassLoader(' | + | |
- | | + | |
* | * | ||
+ | * @author Guilherme Blanco < | ||
* @author Jonathan H. Wage < | * @author Jonathan H. Wage < | ||
* @author Roman S. Borschel < | * @author Roman S. Borschel < | ||
Line 95: | Line 230: | ||
* @author Fabien Potencier < | * @author Fabien Potencier < | ||
*/ | */ | ||
- | class SplClassLoader | + | class SplClassLoader |
{ | { | ||
- | private $_fileExtension | + | |
- | private $_namespace; | + | * @var string |
- | private $_includePath; | + | */ |
- | private $_namespaceSeparator | + | |
+ | |||
+ | /** | ||
+ | * @var boolean | ||
+ | */ | ||
+ | private $includePathLookup = false; | ||
+ | |||
+ | /** | ||
+ | * @var array | ||
+ | */ | ||
+ | private $resources = array(); | ||
+ | |||
+ | /** | ||
+ | * @var integer | ||
+ | */ | ||
+ | private $mode = self:: | ||
/** | /** | ||
- | | + | |
- | * specified namespace. | + | |
- | * | + | |
- | | + | |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | | + | if ($mode & self:: |
- | $this->_includePath | + | throw new \InvalidArgumentException( |
+ | sprintf(' | ||
+ | ); | ||
+ | } | ||
+ | | ||
+ | $this->mode = $mode; | ||
} | } | ||
+ | |||
/** | /** | ||
- | | + | |
* | * | ||
- | * @param string $sep The separator to use. | + | * @param string $fileExtension |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | $this->_namespaceSeparator | + | $this->fileExtension |
} | } | ||
+ | |||
/** | /** | ||
- | | + | |
* | * | ||
- | * @return | + | * @return |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | return $this->_namespaceSeparator; | + | return $this->fileExtension; |
} | } | ||
+ | |||
/** | /** | ||
- | | + | |
* | * | ||
- | * @param | + | * @param |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | $this->_includePath | + | $this->includePathLookup |
} | } | ||
+ | |||
/** | /** | ||
* Gets the base include path for all class files in the namespace of this class loader. | * Gets the base include path for all class files in the namespace of this class loader. | ||
* | * | ||
- | * @return | + | * @return |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | return $this->_includePath; | + | return $this->includePathLookup; |
} | } | ||
+ | |||
/** | /** | ||
- | | + | |
- | * | + | |
- | | + | |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | $this-> | + | |
} | } | ||
+ | |||
/** | /** | ||
- | | + | |
- | * | + | |
- | | + | |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | | + | |
} | } | ||
+ | | ||
/** | /** | ||
- | | + | |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | | + | $this-> |
} | } | ||
+ | | ||
/** | /** | ||
- | | + | |
*/ | */ | ||
- | public function | + | public function |
{ | { | ||
- | | + | |
+ | |||
+ | switch (true) { | ||
+ | case ($this->mode & self:: | ||
+ | if ($resourceAbsolutePath !== false) { | ||
+ | require $resourceAbsolutePath; | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | case ($this-> | ||
+ | default: | ||
+ | require $resourceAbsolutePath; | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | if ($this-> | ||
+ | throw new \RuntimeException( | ||
+ | sprintf('Autoloader expected resource " | ||
+ | | ||
+ | } | ||
} | } | ||
+ | | ||
/** | /** | ||
- | | + | |
* | * | ||
- | * @param string $className The name of the class to load. | + | * @params |
- | * @return | + | * |
+ | * @return | ||
*/ | */ | ||
- | | + | |
{ | { | ||
- | | + | |
- | $fileName = ''; | + | |
- | $namespace = ''; | + | foreach |
- | if (false !== ($lastNsPos = strripos($className, $this-> | + | if (strpos($resourceName, $resource) !== 0) { |
- | | + | |
- | $className | + | } |
- | | + | |
+ | foreach | ||
+ | $resourceAbsolutePath | ||
+ | | ||
+ | if (is_file($resourceAbsolutePath)) { | ||
+ | return | ||
+ | } | ||
} | } | ||
- | $fileName .= str_replace(' | ||
- | |||
- | require ($this-> | ||
} | } | ||
+ | | ||
+ | if ($this-> | ||
+ | return $resourceAbsolutePath; | ||
+ | } | ||
+ | | ||
+ | return false; | ||
+ | } | ||
+ | | ||
+ | /** | ||
+ | * Transform resource name into its relative resource path representation. | ||
+ | * | ||
+ | * @params string $resourceName | ||
+ | * | ||
+ | * @return string Resource relative path. | ||
+ | */ | ||
+ | private function getResourceRelativePath($resourceName) | ||
+ | { | ||
+ | // We always work with FQCN in this context | ||
+ | $resourceName = ltrim($resourceName, | ||
+ | $resourcePath = ''; | ||
+ | | ||
+ | if (($lastNamespacePosition = strrpos($resourceName, | ||
+ | // Namespaced resource name | ||
+ | $resourceNamespace = substr($resourceName, | ||
+ | $resourceName | ||
+ | $resourcePath | ||
+ | } | ||
+ | | ||
+ | return $resourcePath . str_replace(' | ||
+ | } | ||
+ | | ||
+ | /** | ||
+ | * Check if resource is declared in user space. | ||
+ | * | ||
+ | * @params string $resourceName | ||
+ | * | ||
+ | * @return boolean | ||
+ | */ | ||
+ | private function isResourceDeclared($resourceName) | ||
+ | { | ||
+ | return class_exists($resourceName, | ||
+ | || interface_exists($resourceName, | ||
+ | || (function_exists(' | ||
} | } | ||
} | } | ||
</ | </ | ||
- | ===== Example usage ===== | + | If any interested wants to customize the public methods, like caching through APC to reduce I/O, it should be possible |
- | + | ||
- | <code php> | + | |
- | $classLoader = new SplClassLoader(\SplClassLoader:: | + | |
- | $classLoader-> | + | |
- | ' | + | |
- | array('/ | + | |
- | ); // Namespace style | + | |
- | $classLoader-> | + | |
- | $classLoader-> | + | |
- | </ | + | |
===== Proposal and Patch ===== | ===== Proposal and Patch ===== | ||
Line 234: | Line 438: | ||
An extension to SPL has been created from the original C extension and a [[https:// | An extension to SPL has been created from the original C extension and a [[https:// | ||
- | Main purpose of this proposal is to suport | + | Main purpose of this proposal is to support |
- | ===== Implementation extension | + | ===== Changelog |
- | According | + | * 2011-11-09 Christian Kaps: Update examples |
- | * Multiple paths per namespace | + | * 2011-11-08 Guilherme Blanco: Removed constructor prototype and created setMode. |
- | * Silent mode as a flag | + | * 2011-11-08 Guilherme Blanco: Updated SplClassLoader implementation. |
- | + | * 2011-11-07 Guilherme Blanco: Expanded extended rules. | |
- | This turns the RFC specification incompatible with current patch. Patch is going to be updated as soon as voting ends. | + | |
- | + | ||
- | ===== Changelog ===== | + | |
* 2011-10-25 David Coallier: Added the new SPL patch information and feature request link. | * 2011-10-25 David Coallier: Added the new SPL patch information and feature request link. | ||
* 2011-10-24 Guilherme Blanco: Expanded RFC documentation. Put it as ready for review. | * 2011-10-24 Guilherme Blanco: Expanded RFC documentation. Put it as ready for review. | ||
* 2010-03-22 Guilherme Blanco: Initial RFC creation. | * 2010-03-22 Guilherme Blanco: Initial RFC creation. | ||
+ | ===== Comments ===== | ||
+ | * laruence : I have already got a similar loader implemented in Yaf, called Yaf_Loader, you can found the source here: [[yaf_loader][http:// |
rfc/splclassloader.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1