10

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

require( 'config.php' );

class DB {
  // ...
}

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

因此,需要明确的是,数组 $connection_settings 位于 config.php 中,但即使在使用时:

global $connection_settings;

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

有趣的是,即使该类是自动加载的,如果我从 routes.php 文件的顶部包含该类,一切正常。那么,让自动加载以我认为“正常”的方式工作,我做错了什么?

4

2 回答 2

10

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

PHP手册说:

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

下面的代码对我有用(在 PHP 5.4.13 上使用 Laravel 4b4)。删除任一全局行会破坏代码(以不同的方式)。

配置文件

global $connection_settings;
$connection_settings = array(/* ... */);

数据库文件

require 'config.php';
class DB {
    static function connect()
    {
        global $connection_settings;
        // Do something with $connection_settings
    }
}
于 2013-04-08T15:39:47.477 回答
5

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

PHP手册说:

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

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

因此,虽然您可以在 body 中访问此类 var ,但它们其类和函数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());

Foo.php

<?php

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

class Foo
{
    function bar() {
        global $foobar;
        return $foobar;
    }
}

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

于 2018-09-30T06:31:22.330 回答