溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

composer自動加載機制指的是什么

發布時間:2021-01-18 09:39:59 來源:億速云 閱讀:227 作者:小新 欄目:軟件技術

這篇文章主要介紹了composer自動加載機制指的是什么,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

正文

1.了解一下spl_autoload_register

首先查一下php官方手冊:
composer自動加載機制指的是什么
(偷懶可以只看紅色部分即可)

是不是看著一知半解?
來用白話文來翻譯一下:

我們new一個類的話,必須先require或者include類的文件,如果沒有加載進來則會報錯。這產生一個問題:那這樣的話文件的頭部到處都是requies和include,明顯不符合程序員必須"偷懶"尿性。
為了不需要require或者include類文件也能正常的new一個類,出現了自動加載機制。spl_autoload_register這個函數就專門干這個事的。

從截圖得知,此函數有三個參數:

參數詳解
autoload_function這里填的是一個***"函數"的名稱***,字符串或者數組,這個函數的功能就是把需要new的文件require或者include盡量,避免new的時候報錯。簡單的說就是要你封裝一個***自動加載文件的函數***
throw當自動加載的函數無法注冊的時候,是否拋異常
prepend是否添加函數到函數隊列之首,如果是true則為首,否則尾部

來一波代碼,印象深刻一些:

//文件 testClass.php ,即將new的類
class TestClass{
    public function __construct() {
        echo '你已經成功new了我了';
    }
}

//文件autoloadDemo.php文件
spl_autoload_register('autoLoad_function', true, true);
function autoLoad_function($class_name){
    echo "所有的require或者include文件工作都交給我吧!\r\n";
    $class_filename = "./{$class_name}.php";
    echo "我來加載{$class_filename}文件\r\n";
    require_once("./{$class_name}.php");
}
$obj_demo = new TestClass();

輸出:

所有的require或者include文件工作都交給我吧!
我來加載testClass.php文件
你已經成功new了我了

明白了這個加載的原理,看下文就順利多了。

2.composer update發生的故事

將自動加載之前,必須要先說一下composer update,這里頭承載了自動加載的前提。

composer項目都包含一個composer.json的配置文件。
composer自動加載機制指的是什么
這里頭有一個關鍵的字段"autoload",包含psr-4和files兩個字段。

psr-4:說明是基于psr-4規范的類庫,都支持自動加載,只要在后面的對象中以**“命名空間:路徑”**的方式寫入自己的類庫信息即可。
files:這就就更直接了,寫入路徑就自動加載。

按照以上配置每回composer update之后呢,都會更新一個很重要的文件:./vender/composer/autoload_psr4.php。
composer自動加載機制指的是什么

這個文件只做了一件事情:把命名空間和文件路徑對應起來,這樣后續自動加載就有映射根據了。

3.追蹤一下composer的自動加載

composer的故事從唯一的一個require說起:

require '../vendor/autoload.php'

這個腳本執行了一個函數:

ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87::getLoader()

繼續跟getloader函數做了什么?

public static function getLoader() {
   if (null !== self::$loader) {
        return self::$loader;
    }

    spl_autoload_register(array('ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87', 'loadClassLoader'), true, true);
    self::$loader = $loader = new \Composer\Autoload\ClassLoader();
    spl_autoload_unregister(array('ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87', 'loadClassLoader'));

    $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
    if ($useStaticLoader) {
        require_once __DIR__ . '/autoload_static.php';

        call_user_func(\Composer\Autoload\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::getInitializer($loader));
    } else {
        $map = require __DIR__ . '/autoload_namespaces.php';
        foreach ($map as $namespace => $path) {
            $loader->set($namespace, $path);
        }

        $map = require __DIR__ . '/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }

        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }
    }

    $loader->register(true);

    if ($useStaticLoader) {
        $includeFiles = Composer\Autoload\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::$files;
    } else {
        $includeFiles = require __DIR__ . '/autoload_files.php';
    }
    foreach ($includeFiles as $fileIdentifier => $file) {
        composerRequired9b31141b114fcbee3cf55d0e97b7f87($fileIdentifier, $file);
    }

    return $loader;
}

這個函數主要做了兩件事情:
1.將各種存有命名空間和文件映射關系的文件autoload_xxx.php加載了進來,并作了一些處理(比如:setPsr4將相關映射加載了進去,這個留意下,下文會有呼應。)。
2.注冊了函數register

繼續跟蹤register做了什么:

public function register($prepend = false) {
   spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}

原來調用了spl_autoload_register函數,當類沒加載的時候使用loadClass來加載類。(這個前文講的很清楚了,應該很熟了)

繼續跟蹤loadClass實現:

public function loadClass($class) {
	if ($file = $this->findFile($class)) {
		includeFile($file);
		return true;
	}
}

大概可以看出,是做了文件的include。
繼續跟蹤下是怎么查找文件的,看findFile函數:

public function findFile($class) {
    // class map lookup
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];
    }
    if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
        return false;
    }
    if (null !== $this->apcuPrefix) {
        $file = apcu_fetch($this->apcuPrefix.$class, $hit);
        if ($hit) {
            return $file;
        }
    }

    $file = $this->findFileWithExtension($class, '.php');

    // Search for Hack files if we are running on HHVM
    if (false === $file && defined('HHVM_VERSION')) {
        $file = $this->findFileWithExtension($class, '.hh');
    }

    if (null !== $this->apcuPrefix) {
        apcu_add($this->apcuPrefix.$class, $file);
    }

    if (false === $file) {
        // Remember that this class does not exist.
        $this->missingClasses[$class] = true;
    }

    return $file;
}

這個函數做了一件事:就是尋找類從上文的autoload_xxx.php初始化的數據中來尋找映射的文件路徑。
其中這個函數findFileWithExtension,適用于尋找psr-4規范的文件的映射信息的。

繼續跟蹤findFileWithExtension:

private function findFileWithExtension($class, $ext) {
    // PSR-4 lookup
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

    $first = $class[0];
    if (isset($this->prefixLengthsPsr4[$first])) {
        $subPath = $class;
        while (false !== $lastPos = strrpos($subPath, '\\')) {
            $subPath = substr($subPath, 0, $lastPos);
            $search = $subPath.'\\';
            if (isset($this->prefixDirsPsr4[$search])) {
                $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                foreach ($this->prefixDirsPsr4[$search] as $dir) {
                    if (file_exists($file = $dir . $pathEnd)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-4 fallback dirs
    foreach ($this->fallbackDirsPsr4 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
            return $file;
        }
    }

    // PSR-0 lookup
    if (false !== $pos = strrpos($class, '\\')) {
        // namespaced class name
        $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
    } else {
        // PEAR-like class name
        $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
    }

    if (isset($this->prefixesPsr0[$first])) {
        foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
            if (0 === strpos($class, $prefix)) {
                foreach ($dirs as $dir) {
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-0 fallback dirs
    foreach ($this->fallbackDirsPsr0 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
            return $file;
        }
    }

    // PSR-0 include paths.
    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
        return $file;
    }

    return false;
}

這個函數做了件事:將命名空間\類這樣的類名,轉換成目錄名/類名.php這樣的路徑,再從前文setPsr4設置的映射信息中尋找映射信息,然后完成返回路徑。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“composer自動加載機制指的是什么”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女