Laravel 4:为什么我的类自动加载但全局变量不可用

Bri*_*ier 6 laravel laravel-4

我已经自动加载了一个类,它是正确的命名空间和PSR-0.我把它放在app/lib/CI中,类和它的文件名是相同的"DB".类文件本身包含实际类之前的配置文件:

require( 'config.php' );

class DB {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

该类显然是自动加载的,因为当我调用静态方法connect时,它会显示来自:: connect()内部的错误消息.问题是,包含的config.php中的全局变量在class :: method中不可用.

所以,要清楚,数组$ connection_settings在config.php中,但即使使用:

global $connection_settings;
Run Code Online (Sandbox Code Playgroud)

在connect方法中没有设置$ connection_settings.

有趣的是,即使该类是自动加载的,如果我在routes.php文件的顶部包含该类,一切正常.那么我不能正确地按照我认为"正常"的方式进行自动加载?

Phi*_*rks 8

这是Composer而不是Laravel 的问题.Composer尽一切努力在自动加载期间不污染全局范围(在#1297中简要讨论).如果要强制全局变量,则应在配置文件中以及使用它们的任何函数中将它们声明为全局变量.

PHP手册说:

在函数外使用全局关键字不是错误.如果文件包含在函数内部,则可以使用它.

以下代码适用于我(使用PHP 5.4.13上的Laravel 4b4).删除任一全局行会中断代码(以不同方式).

config.php文件

global $connection_settings;
$connection_settings = array(/* ... */);
Run Code Online (Sandbox Code Playgroud)

db.php中

require 'config.php';
class DB {
    static function connect()
    {
        global $connection_settings;
        // Do something with $connection_settings
    }
}
Run Code Online (Sandbox Code Playgroud)


Mes*_*ion 5

这与 Laravel或Composer无关,而是与自动加载机制有关。Phill Sparks 的精彩回答已经指出了使用自动加载包含文件的微妙但至关重要的区别,这是理解和解决问题的关键:

PHP 手册说:

在函数外部使用 global 关键字不是错误。如果该文件包含在函数内部,则可以使用它。

当您使用 autoload via 时spl_autoload_register(),会include发生在autoloader 函数内部。因此,在包含的文件主体中声明的任何变量都不具有全局范围,对于您的变量来说也是如此config.php

因此,虽然您可以在主体中访问此类变量,但它们其类和函数中DB.php不可用。这就是为什么仅在内部使用不起作用:因为这样的变量首先并不是真正的全局变量!globalconnect()

因此,您需要首先global通过在声明它们的同一范围内(在 或DB.phpconfig.php中使用它们来“使”它们成为全局变量,然后在内部global 再次使用connect()来访问此类变量。

一个简单的例子:

test.php:

<?php
spl_autoload_register(function ($class) {
    require(__DIR__.'/'.$class.'.php');
});

$foo = new Foo();
var_dump($foo->bar());
Run Code Online (Sandbox Code Playgroud)

Foo.php:

<?php

global $foobar;
$foobar = "just a test";

class Foo
{
    function bar() {
        global $foobar;
        return $foobar;
    }
}
Run Code Online (Sandbox Code Playgroud)

它工作完美并且可以打印just a test。第一个global 放在 $foobar全局范围内,第二个访问它。删除其中任何一个都会破坏代码,第一个遗漏更“邪恶”,因为它将NULL毫无错误地打印。