我认为对未来的访问者提供一些关于这里发生的事情的解释会很有用。
Illuminate\Http\Request 类
Laravel 的Illuminate\Http\Request 类有一个名为all 的方法(实际上all 方法是在Request 类使用的一个特征中定义的,称为Illuminate\Http\Concerns\InteractsWithInput)。在撰写本文时,all 方法的签名如下所示:
public function all($keys = null)
此方法未定义为static,因此当您尝试在静态上下文中调用该方法时,即Illuminate\Http\Request::all(),您将收到 OP 问题中显示的错误。 all 方法是一个实例方法,它处理存在于 Request 类实例中的信息,因此以这种方式调用它是没有意义的。
外墙
Laravel 中的外观为开发人员提供了一种方便的方式来访问 IoC 容器中的对象,并在这些对象上调用方法。开发人员可以在 Request::all() 这样的外观上“静态地”调用方法,但在 real Illuminate\Http\Request 对象上的实际方法调用不是静态的。
外观就像一个代理——它引用 IoC 容器中的一个对象并将静态方法调用传递给该对象(非静态)。例如,以Illuminate\Support\Facades\Request 外观为例,它的外观是这样的:
class Request extends Facade
{
protected static function getFacadeAccessor()
{
return 'request';
}
}
在底层,Illuminate\Support\Facades\Facade 基类使用了一些 PHP 魔法,即 __callStatic 方法:
- 监听静态方法调用,在本例中为
all,不带参数
- 使用
getFacadeAccessor 返回的键从 IoC 容器中获取底层对象,在本例中为 Illuminate\Http\Request 对象
- 在检索到的对象上动态调用它静态接收的方法,在这种情况下,
all 在Illuminate\Http\Request 的实例上被非静态调用。
这就是为什么正如@patricus 在上面的回答中指出的那样,通过将use/import 语句更改为引用外观,错误不再存在,因为就PHP而言,all已在 Illuminate\Http\Request 的实例上正确调用。
别名
别名是 Laravel 提供的另一个方便的功能。它通过有效地创建指向根命名空间中的外观的别名类来工作。如果您查看config/app.php 文件,在aliases 键下,您会发现一长串字符串到外观类的映射。例如:
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
// ...
'Request' => Illuminate\Support\Facades\Request::class,
Laravel 根据您的配置为您创建这些别名类,这允许您使用根命名空间中可用的类(由 aliases 配置的字符串键引用),就像您使用外观一样本身:
use Request:
class YourController extends Controller
{
public function yourMethod()
{
$input = Request::all();
// ...
}
}
依赖注入注意事项
虽然 Laravel 中仍然提供外观和别名,但可以并且通常鼓励使用依赖注入路线。比如使用构造函数注入来达到同样的效果:
use Illuminate\Http\Request;
class YourController extends Controller
{
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function yourMethod()
{
$input = $this->request->all();
// ...
}
}
这种方法有很多好处,但在我个人看来,依赖注入的最大优点是它使您的代码更容易测试。通过将类的依赖项声明为构造函数或方法参数,可以很容易地模拟出这些依赖项并单独对您的类进行单元测试。