PSR-4 的實現示例
阿新 • • 發佈:2018-06-30
ring pos register dcl else 多個 array void var
閉包實例
<?php /** * 一個具體項目實現的示例。 * * 在註冊自動加載函數後,下面這行代碼將引發程序 * 嘗試從 /path/to/project/src/Baz/Qux.php * 加載 \Foo\Bar\Baz\Qux 類: * * new \Foo\Bar\Baz\Qux; * * @param string $class 完全標準的類名。 * @return void */ spl_autoload_register(function ($class) { // 具體項目的命名空間前綴 $prefix = ‘Foo\\Bar\\‘;// 命名空間前綴對應的基礎目錄 $base_dir = __DIR__ . ‘/src/‘; // 該類使用了此命名空間前綴? $len = strlen($prefix); if (strncmp($prefix, $class, $len) !== 0) { // 否,交給下一個已註冊的自動加載函數 return; } // 獲取相對類名 $relative_class = substr($class, $len); // 命名空間前綴替換為基礎目錄, // 將相對類名中命名空間分隔符替換為目錄分隔符, // 附加 .php$file = $base_dir . str_replace(‘\\‘, ‘/‘, $relative_class) . ‘.php‘; // 如果文件存在,加載它 if (file_exists($file)) { require $file; } });
類實例
<?php namespace Example; /** * 一個多用途的示例實現,包括了 * 允許多個基本目錄用於單個 * 命名空間前綴的可選功能 * * 下述示例給出了一個 foo-bar 類包,系統中路徑結構如下…… * * /path/to/packages/foo-bar/ * src/ * Baz.php # Foo\Bar\Baz * Qux/ * Quux.php # Foo\Bar\Qux\Quux * tests/ * BazTest.php # Foo\Bar\BazTest * Qux/ * QuuxTest.php # Foo\Bar\Qux\QuuxTest * * ……添加路徑到 \Foo\Bar\ 命名空間前綴的類文件中 * 如下所示: * * <?php * // 實例化加載器 * $loader = new \Example\Psr4AutoloaderClass; * * // 註冊加載器 * $loader->register(); * * // 為命名空間前綴註冊基本路徑 * $loader->addNamespace(‘Foo\Bar‘, ‘/path/to/packages/foo-bar/src‘); * $loader->addNamespace(‘Foo\Bar‘, ‘/path/to/packages/foo-bar/tests‘); * * 下述語句會讓自動加載器嘗試從 * /path/to/packages/foo-bar/src/Qux/Quux.php * 中加載 \Foo\Bar\Qux\Quux 類 * * <?php * new \Foo\Bar\Qux\Quux; * * 下述語句會讓自動加載器嘗試從 * /path/to/packages/foo-bar/tests/Qux/QuuxTest.php * 中加載 \Foo\Bar\Qux\QuuxTest 類: * * <?php * new \Foo\Bar\Qux\QuuxTest;*/ class Psr4AutoloaderClass { /** * 關聯數組,鍵名為命名空間前綴,鍵值為一個基本目錄數組。 * * @var array */ protected $prefixes = array(); /** * 通過 SPL 自動加載器棧註冊加載器 * * @return void */ public function register() { spl_autoload_register(array($this, ‘loadClass‘)); } /** * 為命名空間前綴添加一個基本目錄 * * @param string $prefix 命名空間前綴。 * @param string $base_dir 命名空間下類文件的基本目錄 * @param bool $prepend 如果為真,預先將基本目錄入棧 * 而不是後續追加;這將使得它會被首先搜索到。 * @return void */ public function addNamespace($prefix, $base_dir, $prepend = false) { // 規範化命名空間前綴 $prefix = trim($prefix, ‘\\‘) . ‘\\‘; // 規範化尾部文件分隔符 $base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . ‘/‘; // 初始化命名空間前綴數組 if (isset($this->prefixes[$prefix]) === false) { $this->prefixes[$prefix] = array(); } // 保留命名空間前綴的基本目錄 if ($prepend) { array_unshift($this->prefixes[$prefix], $base_dir); } else { array_push($this->prefixes[$prefix], $base_dir); } } /** * 加載給定類名的類文件 * * @param string $class 合法類名 * @return mixed 成功時為已映射文件名,失敗則為 false */ public function loadClass($class) { // 當前命名空間前綴 $prefix = $class; // 通過完整的命名空間類名反向映射文件名 while (false !== $pos = strrpos($prefix, ‘\\‘)) { // 在前綴中保留命名空間分隔符 $prefix = substr($class, 0, $pos + 1); // 其余的是相關類名 $relative_class = substr($class, $pos + 1); // 嘗試為前綴和相關類加載映射文件 $mapped_file = $this->loadMappedFile($prefix, $relative_class); if ($mapped_file) { return $mapped_file; } // 刪除 strrpos() 下一次叠代的尾部命名空間分隔符 $prefix = rtrim($prefix, ‘\\‘); } // 找不到映射文件 return false; } /** * 為命名空間前綴和相關類加載映射文件。 * * @param string $prefix 命名空間前綴 * @param string $relative_class 相關類 * @return mixed Boolean 無映射文件則為false,否則加載映射文件 */ protected function loadMappedFile($prefix, $relative_class) { // 命名空間前綴是否存在任何基本目錄 if (isset($this->prefixes[$prefix]) === false) { return false; } // 通過基本目錄查找命名空間前綴 foreach ($this->prefixes[$prefix] as $base_dir) { // 用基本目錄替換命名空間前綴 // 用目錄分隔符替換命名空間分隔符 // 給相關的類名增加 .php 後綴 $file = $base_dir . str_replace(‘\\‘, ‘/‘, $relative_class) . ‘.php‘; // 如果映射文件存在,則引入 if ($this->requireFile($file)) { // 搞定了 return $file; } } // 找不到 return false; } /** * 如果文件存在從系統中引入進來 * * @param string $file 引入文件 * @return bool 文件存在則 true 否則 false */ protected function requireFile($file) { if (file_exists($file)) { require $file; return true; } return false; } }
PSR-4 的實現示例