doudang4568 2017-09-14 04:52
浏览 59
已采纳

PHP - 为什么代码中对象填充的不同位置会产生不同的结果?

Please note the position of the include_once statement in all the following examples:

This works:

include_once __DIR__ . '/vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;    

$request = Request::createFromGlobals();

echo $request->getMethod();

I thought this wouldn't work, but it does:

use Symfony\Component\HttpFoundation\Request;

include_once __DIR__ . '/vendor/autoload.php';

$request = Request::createFromGlobals();

echo $request->getMethod();

But this fails:

use Symfony\Component\HttpFoundation\Request;    

$request = Request::createFromGlobals();

include_once __DIR__ . '/vendor/autoload.php';

echo $request->getMethod();

So does this:

include_once __DIR__ . '/vendor/autoload.php';

$request = Request::createFromGlobals();

use Symfony\Component\HttpFoundation\Request;

echo $request->getMethod();

I am guessing as long as use and include_once are there in code before the class is used/instantiated, the code would work fine.

Is that right?

A detailed explanation of the flow would be much appreciated.

  • 写回答

2条回答 默认 最新

  • duancan1900 2017-09-14 06:30
    关注

    The execution of a PHP script happens in two phases: first the script is compiled and, if there are no syntax errors, the compiler generates a sequence of so-called "opcodes". Then, the interpreter kicks in and starts the script execution; this means it takes the opcodes one by one, interprets them and performs the operations encoded by them.

    Only the main script is compiled before starting the execution, the files included (using one of the include functions) are compiled during the execution.

    Let's see what happens with your script.

    include_once

    The include/include_once/require/require_once statements generate code that tells the interpreter: "stop the execution of the current script here, load and compile this file and, if it doesn't contain syntax errors, execute its code before continuing this script".

    That's it, the included files are not read during the compilation phase of the main script but only when (and if) they are needed during runtime. In this fragment of code:

    if (false) {
        include 'a.php';
    }
    

    the content of file a.php is never read; even more, the interpreter doesn't even care if the file exists or not. It starts caring about a.php only when the include statement is about to be executed but this never happens because of the if (false) test.

    use

    The use statement is used to create an alias. Such an alias is only an agreement between the programmer and the compiler, the compiler doesn't generate any code for it.

    By using the statement:

    use Symfony\Component\HttpFoundation\Request;
    

    the programmer tells the compiler: "hey, I want you to know that later in this file when you find the token Request I mean \Symfony\Component\HttpFoundation\Request but I prefer to use only Request instead because it's shorter".

    The use statements don't let any trace in the generated code. They do not exist at runtime. The code:

    use Symfony\Component\HttpFoundation\Request;
    $request = new Request();
    

    is the same as:

    $request = new \Symfony\Component\HttpFoundation\Request();
    

    The same code is generated for them; during the compilation, the first form is "transformed" into the second one.

    The autoloader

    The content of file vendor/autoload.php is (probably) the autoloader generated by Composer. An autoloader is a callable (function or class method) registered using spl_autoload_register() that is executed by the interpreter when the code reaches a reference to an unknown class. The autoloader receives the full class name (with namespace) and its purpose is to make the class available. It usually knows where to find the class (in a file). Multiple autoloaders can be registered and the interpreter calls them one by one until the class becomes available or all of them fail.

    How it runs

    Let's replace the alias in your variants of code and see what we get.

    Variants #1 and #2 produce the same code:

    include_once __DIR__ . '/vendor/autoload.php';
    $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
    echo $request->getMethod();
    

    During runtime:

    • the include_once statement loads and registers the autoloader;
    • $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals() - the class \Symfony\Component\HttpFoundation\Request is not known, the interpreter invokes the autoloader that includes the file that declares the class; then the method createFromGlobals of the class is executed and it returns an object of type \Symfony\Component\HttpFoundation\Request;
    • $request is not null and its class implements the method getMethod(); the method is called, the value it returns is displayed by echo, everybody is happy.

    Variant #3:

    $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
    include_once __DIR__ . '/vendor/autoload.php';
    echo $request->getMethod();
    

    How it runs:

    • $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals(); - the class \Symfony\Component\HttpFoundation\Request was not declared yet and there is no autoloader registered - the interpreter cannot find the class, there is no way to continue.

      PHP Fatal error: Class 'Symfony\Component\HttpFoundation\Request' not found.

    Variant #4:

    include_once __DIR__ . '/vendor/autoload.php';
    $request = Request::createFromGlobals();
    echo $request->getMethod();
    

    The alias is not replaced because it is declared after it is used.

    During runtime:

    • the include_once statement loads and registers the autoloader;
    • $request = Request::createFromGlobals(); - the class Request was not defined yet; the interpreter calls the autoloader but the autoloader fails finding it; the interpreter cannot continue.

      Fatal error: Class 'Request' not found

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大