Php 路线中间的可选参数 有没有办法在路由中间添加一个可选参数?

Php 路线中间的可选参数 有没有办法在路由中间添加一个可选参数?,php,laravel,laravel-5,Php,Laravel,Laravel 5,示例路线: /things/entities/ /things/1/entities/ 我试过这个,但不起作用: get('things/{id?}/entities', 'MyController@doSomething'); 我知道我能做到 get('things/entities', 'MyController@doSomething'); get('things/{id}/entities', 'MyController@doSomething'); 。。。但我的问题是:我可以在路

示例路线:

/things/entities/
/things/1/entities/
我试过这个,但不起作用:

get('things/{id?}/entities', 'MyController@doSomething');
我知道我能做到

get('things/entities', 'MyController@doSomething');
get('things/{id}/entities', 'MyController@doSomething');

。。。但我的问题是:我可以在路由的中间添加一个可选参数吗?

不。可选参数需要走到路由的末尾,否则路由器就不知道如何将URL与路由匹配。您已经实施的是正确的方法:

get('things/entities', 'MyController@doSomething');
get('things/{id}/entities', 'MyController@doSomething');
您可以尝试使用一种路线:

get('things/{id}/entities', 'MyController@doSomething');
如果要获取所有对象的实体,请传递*或0,但我称之为hack


有一些其他的黑客可以允许你使用一条路径,但是这会增加代码的复杂性,而且它真的不值得。

在路由定义的中间有可选的参数,只有当参数存在时才会工作。考虑以下事项:

  • 访问路径
    things/1/entities
    时,
    id
    参数将正确获取
    1
    的值
  • 当访问路径
    事物/实体
    时,由于Laravel使用从左到右匹配的正则表达式,因此路径的
    实体
    部分将被视为
    id
    参数的值(因此在本例中
    $id='entitites';
    )。这意味着路由器实际上无法匹配完整的路由,因为
    id
    已匹配,并且它现在希望也有一个尾随的
    /entities
    字符串(因此匹配的路由需要是
    事物/实体/实体
    ,这当然不是我们要的)
因此,您必须采用单独的路线定义方法。

这个问题的“正确”答案是;不,您不能也不应该使用可选参数,除非它位于路由/url的末尾

但是,如果你<强>绝对< /强>需要在路由中间有一个可选的参数,那么有一个方法可以实现。这不是我推荐的解决方案,但您可以这样做:

routes/web.php

// Notice the missing slash
Route::get('/test/{id?}entities', 'Pages\TestController@first')
    ->where('id', '([0-9/]+)?')
    ->name('first');

Route::get('/test/entities', 'Pages\TestController@second')
    ->name('second');
<?php

namespace App\Http\Controllers\Pages;

use App\Http\Controllers\Controller;

class TestController extends Controller
{
    public function first($id = null)
    {
        // If $id is not null, it will have a trailing slash
        $id = rtrim($id, '/');

        return 'First route with: ' . $id;
    }

    public function second()
    {
        return 'Second route';
    }
}
<!-- Notice the trailing slash on id -->
<!-- Will output http://myapp.test/test/123/entities -->
<a href="{{ route('first', ['id' => '123/']) }}">
    First route
</a>

<!-- Will output http://myapp.test/test/entities -->
<a href="{{ route('second') }}">
    Second route
</a>
app/Http/Controllers/Pages/TestController.php

// Notice the missing slash
Route::get('/test/{id?}entities', 'Pages\TestController@first')
    ->where('id', '([0-9/]+)?')
    ->name('first');

Route::get('/test/entities', 'Pages\TestController@second')
    ->name('second');
<?php

namespace App\Http\Controllers\Pages;

use App\Http\Controllers\Controller;

class TestController extends Controller
{
    public function first($id = null)
    {
        // If $id is not null, it will have a trailing slash
        $id = rtrim($id, '/');

        return 'First route with: ' . $id;
    }

    public function second()
    {
        return 'Second route';
    }
}
<!-- Notice the trailing slash on id -->
<!-- Will output http://myapp.test/test/123/entities -->
<a href="{{ route('first', ['id' => '123/']) }}">
    First route
</a>

<!-- Will output http://myapp.test/test/entities -->
<a href="{{ route('second') }}">
    Second route
</a>
这两个链接都将触发
TestController
中的
first
-方法。将永远不会触发第二个
方法

此解决方案适用于Laravel6.3,但不确定其他版本。再一次,这个解决方案不是好的实践