Heim  >  Artikel  >  Backend-Entwicklung  >  PHP-Interviewfrage 4: Autoload implementieren

PHP-Interviewfrage 4: Autoload implementieren

不言
不言Original
2018-04-18 09:40:563290Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Implementierung von Autoload in PHP-Interviewfrage 4. Er hat einen gewissen Referenzwert. Jetzt können Freunde in Not darauf verweisen.

Das Yii-Framework behauptet es Laden eigener Klassen Die Methode ist sehr effizient und wirklich "zeitaufwändiges Laden". Was ist also das Besondere daran? Ich habe heute den Quellcode studiert und festgestellt, dass tatsächlich eine Ebene von „Pfad-Cache“ auf Codeebene hinzugefügt wurde.

Das Autoloading-Prinzip von Yii2

Wir wissen, dass Sie zum Implementieren Ihrer eigenen Autoload-Methode die Funktion spl_autoload_register() verwenden müssen, um eine Autoload-Methode zu registrieren Von Yii registriert ist YiiBase::autoload(), ich werde die Logik dieser Methode später erklären. Darüber hinaus verwendet Yii im Allgemeinen Yii::import($pathAlias, $forceInclude=false), um die entsprechende Klasse zu laden (diese Methode ruft YiiBase::import() direkt auf). Diese Methode kann mit YiiBase::autoload() verwendet werden, um ein „zeitaufwändiges Laden“ zu erreichen.

Lassen Sie uns zunächst über die allgemeine Logik des Imports sprechen:
1. Überprüfen Sie, ob das Array self::$_imports über eine entsprechende Beschreibung verfügt Geladen, geben Sie den Klassennamen oder den Verzeichnisnamen direkt zurück. Fahren Sie andernfalls mit Schritt 2 fort. Erhalten Sie den $pathAliastatsächlichen Pfadnamen
entsprechend dem letzten Teil des Pfadalias ist „*“ Ob es sich bei dem Pfadalias um eine Datei handelt, fahren Sie mit Schritt 3 fort; andernfalls fahren Sie mit Schritt 4 fort true, fordern Sie die Datei sofort an und fügen Sie sie dem Array hinzu. Ein Element . Andernfalls wird ein Element
im Array zwischengespeichert $forceInclude. Für den Pfad lautet der Pfad im Array $_imports zwischengespeichert und ein Element $alias => $className; hinzugefügt. $classMapDa $$className => $realPath standardmäßig false ist, lädt der Import die entsprechende Klasse nicht sofort und lädt sie erst dann tatsächlich, wenn sie verwendet wird. Dies ist die Aufgabe von
. $_includePaths$_imports$alias => $realPathDie allgemeine Logik des automatischen Ladens:

1. Überprüfen Sie, ob der Klassenname im Array forceInclude oder YiiBase::autoload zwischengespeichert wurde. Wenn ja, fordern Sie direkt die entsprechende Datei an Pfad,

ist die Zuordnungstabelle der eigenen Klassen des Frameworks; andernfalls fahren Sie mit Schritt 2 fort. Überprüfen Sie, ob

falsch ist. Wenn ja, fahren Sie mit Schritt 3 fort 3. Durchqueren Sie das Array, verketten Sie den Verzeichnisnamen mit dem Klassennamen, prüfen Sie, ob es sich um eine legale PHP-Datei handelt. Wenn ja, schließen Sie sie ein und springen Sie dann aus der Schleife 4. Ende.
Es ist zu beachten, dass es in der Dokumentation heißt: Wenn Sie es mit anderen Klassenbibliotheken verwenden möchten, müssen Sie $classMap auf false setzen, damit die $_coreClasses-Methoden anderer Klassenbibliotheken bei einem Fehlschlag von $_coreClasses a Chance zur Ausführung.
//YiiBase::$enableIncludePath Ob auf PHP-Include-Pfade zurückgegriffen werden soll, um Klassendateien automatisch zu laden. Der Standardwert ist „true“. Wenn Ihre Hosting-Umgebung es nicht zulässt, den PHP-Include-Pfad zu ändern, können Sie ihn auf „false“ setzen oder Sie möchten einen weiteren Autoloader zum standardmäßigen Yii-Autoloader hinzufügen.include($className . '.php')
Offizielles Beschreibungsdokument$includePaths
In Yii können alle Klassen, Schnittstellen und Eigenschaften vor dem Aufruf mithilfe des automatischen Lademechanismus der Klasse automatisch geladen werden. Yii verwendet den automatischen Klassenlademechanismus von PHP, um die Klassenpositionierung und den Klassenimport effizient zu implementieren. Dieser Mechanismus ist mit dem PSR-4-Standard kompatibel. In Yii werden Klassen nur beim Aufruf geladen, insbesondere Kernklassen, die sehr schnell positioniert werden, was auch ein wichtiger Ausdruck der hohen Effizienz und Leistung von Yii ist.
$enableIncludePathImplementierung des Autoloading-MechanismusYii::autoload()Das automatische Laden von Yii-Klassen basiert auf PHPs spl_autoload_register(), registriert eine eigene Autoloader-Funktion (Autoloader) und fügt sie an der Vorderseite des Autoloader-Funktionsstapels ein wird zuerst aufgerufen. autoload
Die Einführung dieses Mechanismus zum automatischen Laden von Klassen beginnt mit der Eintragsdatei index.php: $enableIncludePath

Der Hauptpunkt dieser Datei ist die Reihenfolge des Drittanbieter-Autoloaders und des Autoloader implementiert von Yii. Unabhängig davon, wie der Code eines Drittanbieters

verwendet, um seinen eigenen Autoloader zu registrieren, kann er sicherstellen, dass er seinen eigenen Autoloader an der Vorderseite des gesamten Autoloder-Stapels einfügen kann, solange der Yii-Code am Ende steht Es kann bei Bedarf das erste sein.

Als nächstes sehen wir uns an, wie Yii

aufruft, um den Autoloader zu registrieren. Es hängt davon ab, was in Yii.php passiert:

Dieser Code ruft

auf, fügen Sie als
<?php
defined(&#39;YII_DEBUG&#39;) or define(&#39;YII_DEBUG&#39;, false);
defined(&#39;YII_ENV&#39;) or define(&#39;YII_ENV&#39;, &#39;prod&#39;);
// 这个是第三方的
autoloaderrequire(__DIR__ . &#39;/../../vendor/autoload.php&#39;);
// 这个是Yii的Autoloader,放在最后面,确保其插入的autoloader会放在最前面
require(__DIR__ . &#39;/../../vendor/yiisoft/yii2/Yii.php&#39;);
// 后面不应再有
autoloader了require(__DIR__ . &#39;/../../common/config/aliases.php&#39;);
$config = yii\helpers\ArrayHelper::merge(    
require(__DIR__ . &#39;/../../common/config/main.php&#39;),    
require(__DIR__ . &#39;/../../common/config/main-local.php&#39;),    
require(__DIR__ . &#39;/../config/main.php&#39;),    
require(__DIR__ . &#39;/../config/main-local.php&#39;)
);
$application = new yii\web\Application($config);
$application->run();
an die Vorderseite des Stapels. Und lesen Sie die Datei „classes.php“ in

ein und speichern Sie eine Zuordnungstabelle. spl_autoload_register()

在上面的代码中,Yii类是里面没有任何代码,并未对 BaseYii::autoload() 进行重载,所以,这个 spl_autoload_register() 实际上将 BaseYii::autoload() 注册为autoloader。如果,你要实现自己的autoloader,可以在 Yii 类的代码中,对 autoload() 进行重载。

在调用 spl_autoload_register() 进行autoloader注册之后,Yii将 calsses.php 这个文件作为一个映射表保存到 Yii::$classMap 当中。这个映射表,保存了一系列的类名与其所在PHP文件的映射关系,比如:

return [  &#39;yii\base\Action&#39; => YII2_PATH . &#39;/base/Action.php&#39;,  &#39;yii\base\ActionEvent&#39; => YII2_PATH . &#39;/base/ActionEvent.php&#39;,  ... ...

  &#39;yii\widgets\PjaxAsset&#39; => YII2_PATH . &#39;/widgets/PjaxAsset.php&#39;,  &#39;yii\widgets\Spaceless&#39; => YII2_PATH . &#39;/widgets/Spaceless.php&#39;,
];

这个映射表以类名为键,以实际类文件为值,Yii所有的核心类都已经写入到这个 classes.php 文件中,所以,核心类的加载是最便捷,最快的。现在,来看看这个关键先生 BaseYii::autoload()

public static function autoload($className){
    if (isset(static::$classMap[$className])) {        
    $classFile = static::$classMap[$className];        if ($classFile[0] === &#39;@&#39;) {            $classFile = static::getAlias($classFile);
        }
    } elseif (strpos($className, &#39;\\&#39;) !== false) {        
    $classFile = static::getAlias(&#39;@&#39; . str_replace(&#39;\\&#39;, &#39;/&#39;,            $className) . &#39;.php&#39;, false);        
    if ($classFile === false || !is_file($classFile)) {            return;
        }
    } else {        
    return;
    }    
    include($classFile);    
    if (YII_DEBUG && !class_exists($className, false) &&
        !interface_exists($className, false) && !trait_exists($className,        false)) {        
        throw new UnknownClassException(        
        "Unable to find &#39;$className&#39; in file: $classFile. Namespace missing?"
        );
    }
}

从这段代码来看Yii类自动加载机制的运作原理:

检查 $classMap[$className] 看看是否在映射表中已经有拟加载类的位置信息;

如果有,再看看这个位置信息是不是一个路径别名,即是不是以 @ 打头, 是的话,将路径别名解析成实际路径。 如果映射表中的位置信息并非一个路径别名,那么将这个路径作为类文件的所在位置。 类文件的完整路径保存在 $classFile ;

如果 $classMap[$className] 没有该类的信息, 那么,看看这个类名中是否含有 \ , 如果没有,说明这是一个不符合规范要求的类名,autoloader直接返回。 PHP会尝试使用其他已经注册的autoloader进行加载。 如果有 \ ,认为这个类名符合规范,将其转换成路径形式。 即所有的 \ 用 / 替换,并加上 .php 的后缀。

将替换后的类名,加上 @ 前缀,作为一个路径别名,进行解析。 从别名的解析过程我们知道,如果根别名不存在,将会抛出异常。 所以,类的命名,必须以有效的根别名打头:

// 有效的类名,因为@yii是一个已经预定义好的别名use yii\base\Application;// 无效的类名,因为没有 @foo 或 @foo/bar 的根别名,要提前定义好use foo\bar\SomeClass;

使用PHP的 include() 将类文件加载进来,实现类的加载。

从其运作原理看,最快找到类的方式是使用映射表。 其次,Yii中所有的类名,除了符合规范外,还需要提前注册有效的根别名。

运用自动加载机制
在入口脚本中,除了Yii自己的autoloader,还有一个第三方的autoloader:

require(__DIR__ . &#39;/../../vendor/autoload.php&#39;);

这个其实是Composer提供的autoloader。Yii使用Composer来作为包依赖管理器,因此,建议保留Composer的autoloader,尽管Yii的autoloader也能自动加载使用Composer安装的第三方库、扩展等,而且更为高效。但考虑到毕竟是人家安装的,人家还有一套自己专门的规则,从维护性、兼容性、扩展性来考虑,建议保留Composer的autoloader。

如果还有其他的autoloader,一定要在Yii的autoloader注册之前完成注册,以保证Yii的autoloader总是最先被调用。

如果你有自己的autoloader,也可以不安装Yii的autoloaer,只是这样未必能有Yii的高效,且还需要遵循一套类似的类命名和加载的规则。就个人的经验而言,Yii的autoloader完全够用,没必要自己重复造轮子。

相关推荐:

php面试题三之yii2和yii的不一样的地方

php面试题二之用到过的传输协议

php面试题一之线程和进程的区别(顺带提下协程)

Das obige ist der detaillierte Inhalt vonPHP-Interviewfrage 4: Autoload implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn