我有一个文件。我们称之为
Foo.php
。看起来像这样:
namespace App\Helpers;
enum FooTypes: string {
case A = "A";
case B = "B";
}
class Foo {
const BAR = "Bar";
// ...
}
这会起作用:
use App\Helpers\{ Foo, FooTypes };
echo Foo::BAR;
echo FooTypes::A->value;
这将失败并出现
"class FooTypes not found"
错误:
use App\Helpers\{ Foo, FooTypes };
// echo Foo::BAR;
echo FooTypes::A->value;
看起来我必须使用“主”类
Foo
才能使用同一文件中的任何枚举。但这似乎有点荒谬。怎么了?我该如何解决这个问题?我也许可以将枚举分成一个单独的文件,但在我的用例中它对我来说确实没有意义。
因为
use
语句在您调用文件中的内容之前不会真正“加载”文件,
当您调用
Foo::BAR
时,它会加载文件 App\Helpers\Foo.php
,因此您可以使用也来自该文件的 FooTypes
。
这里是另一个例子,它可以正常工作,但是如果你注释第一个 return 语句,它会抛出错误
// assume file is in app\Helpers\Foo.php
use \App\Helpers;
// this nonsense doesn't exist, but as long as its not called, theres no problem;
use \Something\That\Dont\Exist;
Route::get('/something', function() {
//Works Fine as it loads app\Helpers\Foo.php first and able to find FooTypes inside that file
return [Helpers\Foo::BAR, Helpers\FooTypes::A];
//trows an error because it tries to load app\Helpers\FooTypes.php first
return [Helpers\FooTypes::A, Helpers\Foo::BAR];
});
use
语句纯粹是一种在特定文件中为不同命名空间中的符号(类、函数、枚举等)提供简写的方法。请参阅 PHP 手册中的使用名称空间:别名/导入。它可以让您输入 echo FooTypes::A->value;
而不是 echo \App\Helpers\FooTypes::A->value;
,但这就是它的 全部。
这与特定符号的定义如何加载完全无关。为此,您可能依赖于autoloading,它会在首次使用特定类/枚举/等时运行回调函数。回调函数通常包含一个定义该符号的文件。
要完全清楚的是,使用use
语句定义符号的别名,不会 触发自动加载器运行。只有实际执行需要该定义的代码才会触发自动加载器。 最常见的约定是将每个定义放入一个单独的文件中,然后配置自动加载器以根据该名称加载文件;但是
这只是一个约定。如果您想有不同的约定,例如任何以“Types”结尾的名称都与没有该结尾的类位于同一文件中,您可以编写一个自动加载函数来实现它。例如:
function my_autoload_callback(string $nameToLoad): void {
$filePath = PROJECT_ROOT . '/' . str_replace('\\', '/', $nameToLoad) . '.php';
if ( file_exists($filePath) ) {
require_once $filePath;
}
else {
// try without "Types" on the end
// should probably have another file_exists check here
require_once str_replace('Types.php', '.php', $filePath);
// we could check if this has found the right class
}
// if the function reaches here without loading the required class,
// you will get a "class not found" error from PHP
}
请注意,自动加载器不知道它是否正在寻找类、接口、特征或枚举;您将获得的唯一输入是完全限定名称,例如 "App\Helpers\FooTypes"
。