问题
I've autoloaded a class, which is properly namespaced and PSR-0. I put it in app/lib/CI, and the class and it's filename are the same "DB". The class file itself includes a config file before the actual class:
require( 'config.php' );
class DB {
// ...
}
The class is clearly autoloading, because when I call the static method connect it does display an error message from inside ::connect(). The problem is, global variables that are inside the included config.php are not available inside the class::method.
So, to be clear, the array $connection_settings is inside config.php, but even when using:
global $connection_settings;
$connection_settings is not set inside the connect method.
Something interesting is that even though the class is autoloaded, if I include the class from the top of my routes.php file, everything works normally. So what am I not doing right to get autoloading to work the way I consider "normal"?
回答1:
This is an issue with Composer rather than Laravel. Composer makes every effort not to pollute the global scope during autoloading (discussed briefly in #1297). If you want to force global variables then you should declare them as global in your config file, as well as in any function using them.
The PHP Manual says:
Using global keyword outside a function is not an error. It can be used if the file is included from inside a function.
The below code works for me (with Laravel 4b4 on PHP 5.4.13). Removing either global line breaks the code (in different ways).
config.php
global $connection_settings;
$connection_settings = array(/* ... */);
DB.php
require 'config.php';
class DB {
static function connect()
{
global $connection_settings;
// Do something with $connection_settings
}
}
回答2:
This has nothing to do with either Laravel or Composer, but rather with autoload mechanics. Phill Sparks' great answer already pointed out a subtle yet crucial difference of including files using autoload, and that's the key to understand and solve your problem:
The PHP Manual says:
Using global keyword outside a function is not an error. It can be used if the file is included from inside a function.
When you use autoload via spl_autoload_register()
, the include
happens inside the autoloader function. So any variables declared in the included file body does not have global scope, the same for your config.php
vars.
So, while you can access such vars in DB.php
body, they are not available inside its classes and functions. That's why using global
just inside connect()
does not work: because such vars are not really global in the first place!
So you need to "make" them global first, by using global
in the same scope where they were declared (either at DB.php
or config.php
) and then use global
again inside connect()
to access such vars.
A simple example:
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;
}
}
It works perfectly and prints just a test
. The first global
puts $foobar
at global scope, the second one access it. Removing either will break the code, the first omission being more "evil", as it will print NULL
with no errors.
来源:https://stackoverflow.com/questions/15676353/laravel-4-why-does-my-class-autoload-but-global-variables-are-not-available