1. 程式人生 > >PSR-4 的實現示例

PSR-4 的實現示例

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 的實現示例