Thinkphp Series: How the automatic loading of classes is designed

Source: Internet
Author: User
Tags autoload rtrim traits

When using framework development, you can see that there are many core classes in the framework, but it is seldom seen that the code that introduces a file is displayed because the framework uses the automatic loading mechanism of the class, and even when the class is used, the framework automatically finds the location of the file where the class is located and introduces the file.

To make it easier to see the code ideas, the following is the main code that is extracted from the description.

In the analysis of Thinkphp source code, first say I do a project implementation of the automatic loading ideas.
Determine the location of the file according to the file naming feature.

Entry File Code:

Entry file index.php
Require_once (' base.php ');

if (function_exists (' Spl_autoload_register ')) {
Spl_autoload_register (Array (' Base ', ' autoload '));
} else {
function __autoload ($class) {
Return Base::autoload ($class);
}
}

base.php

Final class base{
public static function AutoLoad ($class) {

$class = Strtolower ($class);
if (Ucwords (substr ($class, 0,5)) = = ' Cache ' && $class! = ' cache ') {

if ([Email protected]_once (Base_core_cache_path. Ds.substr ($class, 0,5). SUBSTR ($class, 5). php ')) {
Exit ("Class Error: {$class}.isn ' t exists!");
}
}elseif ($class = = ' db ') {
if ([Email protected]_once (Base_core_path. DS. ' DB '. Ds.strtolower (Dbdriver). php ')) {
Exit ("Class Error: {$class}.isn ' t exists!");
}
}else{

if ([Email protected]_once (Base_lib_path. DS. $class. php ')) {
Exit ("Class Error: {$class}.isn ' t exists!");
}
}
}
}

As the code shows, when the class is used with the CACHE, the class file is looked up from Base_core_cache_path. The default is to look for it from Base_lib_path.

Now let's take a look at how the thinkphp framework is done.

start.php Portal File
namespace think;

thinkphp Boot file
Loading the underlying file
Require ' base.php ';
Perform the application
App::run ()->send ();
base.php file

Load Loader class
Require ' loader.php ';
Register for automatic loading
\think\loader::register ();
loader.php file
namespace think;
Class loader{
public static function Register ($autoload = ")
{
Spl_autoload_register ($autoload?: ' Think\\loader::autoload ', true, true);
}

Auto Load
public static function AutoLoad ($class)
{
echo ' Enter autoload<br> ';
echo $class [0]. ' <br> ';
Var_dump ($class);
}
}

By walking down the process as above, it is possible to finally know that the framework's automatic loading function is implemented primarily in the AutoLoad method of the loader class.
The above code can be self-built a small project run, if the project name is test, browser access

http://localhost/test/start.php

The following results can be obtained:

Enter AutoLoad
T
String (9) "Think\app"Fatal error: E:\xampp\htdocs\test\start.php9

From the result can be judged out when the execution

App::run ()->send ();

When the code is here, the framework has successfully entered the way to implement the automatic loading mechanism.

Then take a closer look at how the next thinkphp framework introduces the file where this app class resides.
Add more detail to the above file code as follows:

start.php Portal File
namespace think;
Define (' DS ', directory_separator);
Define (' EXT ', '. php ');
Define (' Lib_path ', __dir__. DS. ' Library '. DS);

thinkphp Boot file
Loading the underlying file
Require ' base.php ';
Perform the application
App::run ()->send ();


Then the new app class file, if successfully entered the Run method, indicates that the app class automatically loaded successfully.

<?php
library/think/app.php
namespace think;
Class APP
{
public static function run ()
{
echo ' Enter run<br> ';
}
}

loader.php file changes slightly more, see the code:

<?php
loader.php file
namespace think;
Class loader{

PSR-4
private static $PREFIXLENGTHSPSR 4 = [];
private static $PREFIXDIRSPSR 4 = [];

public static function Register ($autoload = ")
{
Spl_autoload_register ($autoload?: ' Think\\loader::autoload ', true, true);

Registering namespace Definitions
Self::addnamespace ([
' Think ' = Lib_path. ' Think '. Ds
' Behavior ' = Lib_path. ' Behavior '. Ds
' Traits ' = Lib_path. ' Traits '. Ds
]);

Var_dump (self:: $PREFIXLENGTHSPSR 4);
}

Auto Load
public static function AutoLoad ($class)
{
echo ' Enter autoload<br> ';
echo $class [0]. ' <br> ';
Var_dump ($class);

if ($file = Self::findfile ($class)) {
Include ($file);
return true;
}
}

/**
* Find Files
* @param $class
* @return BOOL
*/
private static function FindFile ($class)
{
Find PSR-4
$LOGICALPATHPSR 4 = STRTR ($class, ' \ \ ', DS). EXT;

$first = $class [0];
if (Isset (self:: $PREFIXLENGTHSPSR 4[$first])) {
foreach (self:: $PREFIXLENGTHSPSR 4[$first] as $prefix = = $length) {
if (0 = = Strpos ($class, $prefix)) {
foreach (self:: $PREFIXDIRSPSR 4[$prefix] as $dir) {
if (is_file ($file = $dir. Ds. SUBSTR ($LOGICALPATHPSR 4, $length))) {
return $file;
}
}
}
}
}
}


Registering a Namespace
public static function AddNamespace ($namespace, $path = ")
{
if (Is_array ($namespace)) {
foreach ($namespace as $prefix = = $paths) {
SELF::ADDPSR4 ($prefix. ' \ \ ', RTrim ($paths, DS), true);
}
} else {
SELF::ADDPSR4 ($namespace. ' \ \ ', RTrim ($path, DS), true);
}
}

Add PSR4 Space
private static function AddPsr4 ($prefix, $paths, $prepend = False)
{
if (! $prefix) {

} elseif (!isset (self:: $PREFIXDIRSPSR 4[$prefix])) {
Register directories for a new namespace.
$length = strlen ($prefix);
if (' \ \ '!== $prefix [$length-1]) {
throw new \invalidargumentexception ("A non-empty PSR-4 prefix must end with A namespace separator.");
}
Self:: $PREFIXLENGTHSPSR 4[$prefix [0]][$prefix] = $length;
Self:: $PREFIXDIRSPSR 4[$prefix] = (array) $paths;
} elseif ($prepend) {

} else {

}
}

}


The contents of the base.php file are unchanged.
Now let's comb the Code execution order (from top to bottom):

---\think\loader::register ()
---spl_autoload_register (' think\\loader::autoload ')
---\think\loader::addnamespace ()
---\THINK\LOADER::ADDPSR4 ()
---\think\loader::autoload ()
---\think\loader::findfile ()
---app::run ()

Where the AddNamespace AddPsr4 method stores the actual directory corresponding to the partial namespace into the static array variable.
Print the contents of the two variables $prefixlengthspsr4 and $PREFIXDIRSPSR4, and get the following as follows:

Array (2) {  ["T"]=>  Array (2) {    ["Think\"]=>int (6)    ["Traits\"]=>int (7)  }  ["B"]= >  Array (1) {    ["behavior\"]=>int (9)  }}
Array (3) {  ["think\"]=>  Array (1) {    [0]=>string] "E:\xampp\htdocs\test\library\think"  }  ["behavior\"]=>  Array (1) {    [0]=>    string (PNS) "E:\xampp\htdocs\test\library\behavior"  }  ["traits\"]=>  Array (1) {    [0]=>    string ("E:\xampp\htdocs\test\library\traits"  } }

And then into the AutoLoad findfile this step, analyzed as follows:

Before testing AutoLoad method, learned $class = ' think\app '; $class [0] = ' t ';

Replace the backslash in the $class string with the file delimiter,
Then the file suffix becomes ' think/app.php '.
Note: The namespace delimiter is still in the $class variable
$LOGICALPATHPSR 4 = STRTR ($class, ' \ \ ', DS). EXT;

$first = $class [0];
$class = ' Think\app ';
$prefix = ' think\ ';
if (Isset (self:: $PREFIXLENGTHSPSR 4[$first])) {
foreach (self:: $PREFIXLENGTHSPSR 4[$first] as $prefix = = $length) {
if (0 = = Strpos ($class, $prefix)) {
foreach (self:: $PREFIXDIRSPSR 4[$prefix] as $dir) {

+ think/app.php intercept think/left after the app.php
if (is_file ($file = $dir. Ds. SUBSTR ($LOGICALPATHPSR 4, $length))) {
return $file;
}
}
}
}
}

Here are 2 points to note:
1. Here the backslash symbol in the prefix variable is added when executing the code below.

SELF::ADDPSR4 ($prefix. ' \ \ ', RTrim ($paths, DS), true);

The purpose of the backslash is to more precisely determine the namespace, which represents the end of a segment of the namespace. By using the code logic above, you can prevent confusion with thinkme-like namespaces that are prefixed with think.

2. The main idea of searching for documents according to the carding summary as above:

File location = Folder location for custom namespaces + file delimiter + truncated class namespace and remainder class name + file suffix


The above carding process greatly simplifies the automatic loading mechanism of thinkphp framework, and selects only one of the cases to analyze and explain.
More understanding will be further updated here in the future.

The code in this article has a backup on GitHub and is welcome to download. Link Address: Https://github.com/bingodawson/tpautoload.git


Thinkphp Series: How the automatic loading of classes is designed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.