Maison  >  Article  >  développement back-end  >  Question d'entretien PHP 4 : Implémentation du chargement automatique

Question d'entretien PHP 4 : Implémentation du chargement automatique

不言
不言original
2018-04-18 09:40:563290parcourir

Le contenu de cet article concerne l'implémentation du chargement automatique dans la question 4 de l'entretien PHP. Il a une certaine valeur de référence. Maintenant, je le partage avec vous. Les amis dans le besoin peuvent s'y référer

Le framework Yii revendique son. propre chargement de classe La méthode est très efficace et est un véritable "chargement qui prend beaucoup de temps" Alors, quelle est sa particularité ? J'ai étudié le code source aujourd'hui et j'ai découvert qu'une couche de "path cache" avait en fait été ajoutée au niveau du code.

Le principe de chargement automatique de Yii2

Nous savons que pour implémenter votre propre méthode de chargement automatique, vous devez utiliser la fonction spl_autoload_register() pour enregistrer une méthode de chargement automatique Cette méthode. enregistré par Yii est YiiBase::autoload(), j'expliquerai la logique de cette méthode plus tard. De plus, Yii utilise généralement Yii::import($pathAlias, $forceInclude=false) pour charger la classe correspondante (cette méthode appelle directement YiiBase::import() Cette méthode peut être utilisée avec YiiBase::autoload() pour réaliser un « chargement fastidieux »).

Parlons d'abord de la logique générale de l'importation :
1. Vérifiez si le tableau self::$_imports a un $pathAlias correspondant. chargé, renvoie directement le nom de la classe ou le nom du répertoire ; sinon, passez à l'étape 2
Obtenez le nom du chemin réel en fonction de l'alias du chemin, et sachez s'il faut charger en fonction de la dernière partie. de l'alias du chemin est "*" Si l'alias du chemin est un fichier, s'il s'agit d'un fichier, passez à l'étape 3 ; sinon, passez à l'étape 4 ; true, exigez immédiatement le fichier et ajoutez-le au tableau
Un élément $forceInclude Sinon, un élément $_imports sera mis en cache dans le tableau $alias => $className; Pour le chemin, le chemin sera mis en cache dans le tableau $classMap, et un élément $className => $realPath > ;
Parce que $$_includePaths est faux par défaut, import ne chargera pas la classe correspondante immédiatement et ne la chargera pas réellement tant qu'elle ne sera pas utilisée. C'est le travail de $_imports. $alias => $realPath

La logique générale du chargement automatique : forceInclude YiiBase::autoload1. Vérifiez si le nom de la classe a été mis en cache dans le tableau

ou

Si c'est le cas, demandez directement le fichier correspondant. path, est la table de mappage des propres classes du framework ; sinon passez à l'étape 2 2 Vérifiez si
est faux, si c'est le cas, passez à l'étape 3, sinon directement $classMap $_coreClasses. 3. Parcourez $_coreClasses Array, concaténez le nom du répertoire avec le nom de la classe, vérifiez s'il s'agit d'un fichier php légal, si c'est le cas, incluez-le, puis sortez de la boucle
4. Terminez. YiiBase::$enableIncludePathIl est à noter que la documentation indique : Si vous souhaitez l'utiliser avec d'autres bibliothèques de classes, vous devez définir include($className . '.php') sur false afin que lorsque
échoue, les méthodes $includePaths des autres bibliothèques de classes aient un chance d'exécuter.
//
S'il faut s'appuyer sur PHP pour inclure les chemins pour charger automatiquement les fichiers de classe. La valeur par défaut est true. Si votre environnement d'hébergement ne vous permet pas de modifier le chemin d'inclusion PHP, vous pouvez le définir sur false, ou vous souhaitez ajouter un autre chargeur automatique au chargeur automatique Yii par défaut.$enableIncludePathYii::autoload()Document de description officielautoload
Dans Yii, toutes les classes, interfaces et traits peuvent être automatiquement chargés avant d'être appelés à l'aide du mécanisme de chargement automatique de la classe. Yii utilise le mécanisme de chargement automatique des classes de PHP pour implémenter efficacement le positionnement et l'importation des classes. Ce mécanisme est compatible avec la norme PSR-4. Dans Yii, les classes ne sont chargées que lorsqu'elles sont appelées, en particulier les classes principales, qui sont positionnées très rapidement, ce qui est également une manifestation importante de la haute efficacité et des hautes performances de Yii. $enableIncludePath

Implémentation du mécanisme de chargement automatique

Le chargement automatique des classes de Yii repose sur spl_autoload_register() de PHP, enregistrez votre propre fonction de chargement automatique (autoloader) et insérez-la à l'avant de la pile de fonctions de chargement automatique. Assurez-vous que le chargeur automatique de Yii. est appelé en premier.

L'introduction de ce mécanisme de chargement automatique de classe commence par le fichier d'entrée index.php :


Le point principal de ce fichier est l'ordre de l'autochargeur tiers et le chargeur automatique implémenté par Yii . Quelle que soit la manière dont le code tiers utilise

pour enregistrer son propre chargeur automatique, tant que le code Yii est à la fin, il peut garantir qu'il peut insérer son propre chargeur automatique à l'avant de toute la pile du chargeur automatique, de sorte que cela peut être le premier en cas de besoin.

Ensuite, voyons comment Yii appelle
<?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();
pour enregistrer l'autochargeur. Cela dépend de ce qui se passe dans Yii.php :

spl_autoload_register()

Ce code appelle

, insérez comme spl_autoload_register() à l'avant de la pile. Et lisez classes.php dans

et enregistrez une table de mappage.
<?php
require(__DIR__ . &#39;/BaseYii.php&#39;);
class Yii extends \yii\BaseYii{}
// 重点看这个 
spl_autoload_registerspl_autoload_register([&#39;Yii&#39;, &#39;autoload&#39;], true, true);
// 下面的语句读取了一个映射表
Yii::$classMap = include(__DIR__ . &#39;/classes.php&#39;);

Yii::$container = new yii\di\Container;

在上面的代码中,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面试题一之线程和进程的区别(顺带提下协程)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn