Laravel 路由中的 PHP 原生类型提示
我未考虑的东西是Laravel控制器中的临界原始类型。 PHP只有四种标量原始类型: 布尔型, 整型, 浮点型,和字符串, 你可能最想要的是字符串和整型。 但是, 我通常不会在我的控制器中输入提示标量类型。
我最近看到由于类型错误导致的type-hinting controller突然出现问题,因此我想演示一些例子,您可以在其中安全地使用整型的type-hinted controllers。
请看以下路由操作并考虑调用的$orderid是哪种类型
Route::get('/order/{order_id}', function ($orderId) {
return [
'type' => gettype($orderId),
'value' => $orderId,
];
});
调用此闭包时,$orderId将是一个字符串。如果您编写了一个快速测试,您将看到下面的结果:
/**
* 一个基本的测试示例。
*
* @return void
*/
public function test_example()
{
$response = $this->get('/order/123');
$response->assertJson([
'type' => 'string',
'value' => '123',
]);
}
现在,假设您希望order id始终是一个整数,因此希望键入提示参数:
Route::get('/order/{order_id}', function (int $orderId) {
return [
'type' => gettype($orderId),
'value' => $orderId,
];
});
如果您返回测试,现在它将失败,并显示以下输出:
--- Expected
+++ Actual
@@ @@
array (
- 'type' => 'string',
- 'value' => '123',
+ 'type' => 'integer',
+ 'value' => 123,
)
虽然我们从技术上讲是将123
的字符串
传递给路由函数,PHP通过默认类型强制转换来处理这个问题。 换句话说,当调用route函数时,PHP尝试将值从字符串转换为整数。
虽然从技术上讲,这种方法可以生效并保证为整数
类型,但您可能已经发现了另一个问题:如果用户传递的内容无法从字符串转换为整数,该怎么办?
如果将测试更新为以下的内容,我们将得到一个 TypeError:
public function test_example()
{
$this->withoutExceptionHandling();
$response = $this->get('/order/ABC-123');
$response->assertJson([
'type' => 'integer',
'value' => 123,
]);
}
运行测试会给你以下错误:
TypeError: Illuminate\Routing\RouteFileRegistrar::{closure}():
Argument #1 ($orderId) must be of type int, string given, called in .../vendor/laravel/framework/src/Illuminate/Routing/Route.php on line 238
如果我们想在路由中输入一个整数,我们应该确保我们的路由有一个 正则表达式约束:
Route::get('/order/{order_id}', function (int $orderId) {
return [
'type' => gettype($orderId),
'value' => $orderId,
];
})->where('order_id', '[0-9]+');
添加路由参数约束后,只有数值会匹配路由,从而确保类型强制按预期工作。 以下测试将更准确,以确保您无法将订单路由与非数字路由器参数匹配:
public function test_example()
{
$response = $this->get('/order/ABC-123');
$response->assertNotFound();
}
现在如果你想要使用类型提示,您可以假设你的闭包路由的类型安全地强制转换为整数。虽然用例有限,但我认为了解此细微差别能够帮助人们更好的尝试输入类型提示路由参数。
严格类型对此有何影响?
我想声明 declare(strict_types=1);
没有任何效果,因为调用代码在 Laravel 框架中,不使用strict_types
声明,因此将出现类型强制:
- Laravel’s Controller::callAction() 对于控制器
- Laravel’s Route::runCallable() 对于闭包路由
在PHP的类型 [声明文档]中(www.php.net/manual/en/language.typ...), 关于严格类型的工作原理,严格类型有以下说明:
严格类型适用于启用严格类型的文件中*的函数调用,而不适用于该文件中声明的函数。如果未启用严格类型的文件调用在具有严格类型的文件中定义的函数,将遵守调用方的首选项(强制类型),并且该值将被强制。
替代方法
如果控制器和闭包中有标量路由参数,则可以省略标量类型并在控制器方法中执行类型转换:
Route::get(
'/order/{order_id}',
function ($orderId, SomeService $someService) {
// Cast for a method that strictly type-hints an integer
$result = $someService->someMethod((int) $orderId);
// ...
}
);
大多数的时候, 你会用 路由模型绑定 用于路由参数匹配数字ID; 当您有一个数字路由参数要使用原始标量类型int
进行类型提示时,请考虑这种方法.
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: