升級指南
高度影響的更改
中度影響的更改
從 7.x 升級到 8.0
預計升級所需時間:15 分鐘
We attempt to document every possible breaking change. Since some of these breaking changes are in obscure parts of the framework only a portion of these changes may actually affect your application.
最低版本要求為 PHP 7.3.0
受影響的可能性:中等
最低要求的 PHP 版本現為 7.3.0
相依性套件更新
請在 composer.json
檔案中更新下列相依性套件:
-
guzzlehttp/guzzle
to^7.0.1
-
facade/ignition
to^2.3.6
-
laravel/framework
to^8.0
-
laravel/ui
to^3.0
-
nunomaduro/collision
to^5.0
-
phpunit/phpunit
to^9.0
下列第一方專案也有更新新的版本以支援 Laravel 8。若有使用這些套件,請在升級前先閱讀各套件的升級指南:
此外,Laravel Installer 也更新了對 composer create-project
與 Laravel Jetstream 的支援。從 2020 年 10 月起,4.0 版以前的安裝程式將停止運作。請儘快將全域的 Installer 升級至 ^4.0
。
最後,請檢視你的專案使用的其他第三方套件,確認一下是否有使用支援 Laravel 8 的版本。
Collections
isset
方法
受影響的可能:低
為了與一般 PHP 的行為保持一致,Illuminate\Support\Collection
的 offsetExists
方法已從 array_key_exists
改為使用 isset
。因此,在處理值為 null
的 Collection 項目時的行為可能會有所變更:
1$collection = collect([null]);23// Laravel 7.x - true4isset($collection[0]);56// Laravel 8.x - false7isset($collection[0]);
1$collection = collect([null]);23// Laravel 7.x - true4isset($collection[0]);56// Laravel 8.x - false7isset($collection[0]);
資料庫
Seeder 與 Factory 的 Namespace
受影響的可能:高
Seeder 與 Factory 現在被放到 Namespace 下了。為了符合這項更改,請在 Seeder 類別中加上 Database\Seeders
Namespace。此外,原本的 database/seeds
目錄也應重新命名為 database/seeders
:
1<?php23namespace Database\Seeders;45use App\Models\User;6use Illuminate\Database\Seeder;78class DatabaseSeeder extends Seeder9{10 /**11 * Seed the application's database.12 *13 * @return void14 */15 public function run()16 {17 ...18 }19}
1<?php23namespace Database\Seeders;45use App\Models\User;6use Illuminate\Database\Seeder;78class DatabaseSeeder extends Seeder9{10 /**11 * Seed the application's database.12 *13 * @return void14 */15 public function run()16 {17 ...18 }19}
若要使用 laravel/legacy-factories
套件,則不需更改 Factory 類別。不過,如果要更新 Factory,則應在這些類別內加上 Database\Factories
Namespace。
接著,在 composer.json
檔案中,請從 autoload
段落中移除 classmap
區塊,並為這些新放進 Namespace 的類別加上目錄映射:
1"autoload": {2 "psr-4": {3 "App\\": "app/",4 "Database\\Factories\\": "database/factories/",5 "Database\\Seeders\\": "database/seeders/"6 }7},
1"autoload": {2 "psr-4": {3 "App\\": "app/",4 "Database\\Factories\\": "database/factories/",5 "Database\\Seeders\\": "database/seeders/"6 }7},
Eloquent
Model Factory
受影響的可能:高
Laravel 的 [Model Factory] 功能已完全重寫以支援新的類別格式的寫法,因此已不相容於 Laravel 7.x 風格的 Factory。不過,為了使升級過程更簡單,我們建立了新的 laravel/legacy-factories
套件,可讓你繼續在 Laravel 8.x 中使用現有的 Factory。可使用 Composer 來安裝這個套件:
1composer require laravel/legacy-factories
1composer require laravel/legacy-factories
Castable
介面
受影響的可能:低
Castable
介面的 castUsing
方法已更新為接受一組陣列的引數。若你有實作這個介面,請更新該實作:
1public static function castUsing(array $arguments);
1public static function castUsing(array $arguments);
遞增與遞減的事件
受影響的可能:低
現在,在 Eloquent Model 實體上執行 increment
或 decrement
方法時,會分派相應與「update」與「save」相應的 Model 事件。
事件
EventServiceProvider
類別
受影響的可能:低
如果你的 App\Providers\EventServiceProvider
類別內有包含 register
方法,請確認是否有在此方法的開頭呼叫 parent::register
。若未呼叫 parent::register
會導致專案中的事件不被註冊。
Dispatcher
Contract
受影響的可能:低
Illuminate\Contracts\Events\Dispatcher
Contract 的 listen
方法已將 $listener
屬性改為可選屬性。此修改是為了要支援使用 Reflection 來自動偵測所處理的 Event 型別。若有手動實作此介面,請更改你的實作:
1public function listen($events, $listener = null);
1public function listen($events, $listener = null);
Laravel Framework
維護模式更新
受影響的可能性:可選
在 Laravel 8.x 中,Laravel 的維護模式已獲得了改進。現在已支援了預先轉譯的維護模式樣板,並可減少終端使用者在維護模式時遇到錯誤的機會。不過,為了支援此功能,必須在 public/index.php
中加上下列更改。這幾行程式碼必須被緊接著放在現有的 LARAVEL_START
常數定義之後:
1define('LARAVEL_START', microtime(true));23if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {4 require $maintenance;5}
1define('LARAVEL_START', microtime(true));23if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {4 require $maintenance;5}
php artisan down --message
選項
受影響的可能性:中等
php artisan down
指令的 --message
選項已被移除。作為替代方案,請考慮使用所需的訊息來預先轉譯維護模式的 View。
php artisan serve --no-reload
選項
受影響的可能:低
php artisan serve
指令新增了一個 --no-reload
選項。該選項可讓內建的 Server 在偵測到環境變數檔更改時不要自動重新載入。在 CI 環境中執行 Laravel Dusk 測試時特別適合使用此選項。
Manager 的 $app
屬性
受影響的可能:低
原本在 Illuminate\Support\Manager
類別上停止支援 (Deprecated) 的 $app
屬性現已移除。若你需要使用此屬性,請改用 $container
屬性。
elixir
輔助函式
受影響的可能:低
原本停止支援 (Deprecated) 的 elixir
輔助函式現已被移除。建議使用此方法的專案升級為使用 Laravel Mix。
郵件
sendNow
方法
受影響的可能:低
原本停止支援 (Deprecated) 的 sendNow
方法現已移除。請改用 send
方法。
分頁
分頁的預設
受影響的可能:高
Paginator 現在使用 Tailwind CSS Framework 作為其預設樣式。若要繼續使用 Bootstrap,請在專案的 AppServiceProvider
中 boot
方法內加上下列方法呼叫:
1use Illuminate\Pagination\Paginator;23Paginator::useBootstrap();
1use Illuminate\Pagination\Paginator;23Paginator::useBootstrap();
佇列
retryAfter
方法
受影響的可能:高
為了與 Laravel 中的其他功能保持一致性,放入佇列的 Job、Mailer、Notification、與 Lisenter 上的retryAfter
方法與 retryAfter
屬性已重新命名為 backoff
。請在專案內的相應類別中更新此方法/屬性名稱。
timeoutAt
屬性
受影響的可能:高
放入佇列的 Job、Notification、Listener 的 timeoutAt
屬性已被重新命名為 retryUntil
。請在專案中相應類別上更新此屬性的名稱。
allOnQueue()
與 allOnConnection()
方法
受影響的可能:高
為了與其他分派方法保持一致,在 Job 串聯中使用的 allOnQueue()
與 allOnConnection()
方法已被移除。請使用 onQueue()
與 onConnection()
方法代替。這些方法應在呼叫 dispatch
方法前呼叫:
1ProcessPodcast::withChain([2 new OptimizePodcast,3 new ReleasePodcast4])->onConnection('redis')->onQueue('podcasts')->dispatch();
1ProcessPodcast::withChain([2 new OptimizePodcast,3 new ReleasePodcast4])->onConnection('redis')->onQueue('podcasts')->dispatch();
請注意,此更改只會影響有使用 withChain
方法的程式。使用全域的 dispatch
輔助函式時,仍然可使用 allOnQueue()
與 allOnConnection()
。
失敗 Job 資料表的批次支援
受影響的可能性:可選
若要使用 Laravel 8.x 的 Job 批次功能,則必須更新 failed_jobs
資料庫資料表。首先,需要在資料表中加上一個新的 uuid
欄位:
1use Illuminate\Database\Schema\Blueprint;2use Illuminate\Support\Facades\Schema;34Schema::table('failed_jobs', function (Blueprint $table) {5 $table->string('uuid')->after('id')->nullable()->unique();6});
1use Illuminate\Database\Schema\Blueprint;2use Illuminate\Support\Facades\Schema;34Schema::table('failed_jobs', function (Blueprint $table) {5 $table->string('uuid')->after('id')->nullable()->unique();6});
接著,在 queue
設定檔中的 failed.driver
設定選項應更新為 database-uuids
。
此外,你可能也會想為現有的失敗 Job 產生 UUID:
1DB::table('failed_jobs')->whereNull('uuid')->cursor()->each(function ($job) {2 DB::table('failed_jobs')3 ->where('id', $job->id)4 ->update(['uuid' => (string) Illuminate\Support\Str::uuid()]);5});
1DB::table('failed_jobs')->whereNull('uuid')->cursor()->each(function ($job) {2 DB::table('failed_jobs')3 ->where('id', $job->id)4 ->update(['uuid' => (string) Illuminate\Support\Str::uuid()]);5});
路由
Controller 的自動 Namespace 前置詞
受影響的可能性:可選
在過往版本的 Laravel 中,RouteServiceProvider
類別包含了一個 $namespace
屬性,該屬性的值為 App\Http\Controllers
。這個屬性的值是用來在 Controller 的 Route 定義與使用 action
輔助函式來產生 Controller Route URL 時自動為 Controller 加上前置詞用的。
在 Laravel 8 中,此屬性預設被設為 null
。這樣一來,你就可以在 Controller Route 定義中使用標準的 PHP Callable 語法。這種語法對於大多數 IDE 來說支援度也更高,可直接跳至 Controller 類別:
1use App\Http\Controllers\UserController;23// Using PHP callable syntax...4Route::get('/users', [UserController::class, 'index']);56// Using string syntax...7Route::get('/users', 'App\Http\Controllers\UserController@index');
1use App\Http\Controllers\UserController;23// Using PHP callable syntax...4Route::get('/users', [UserController::class, 'index']);56// Using string syntax...7Route::get('/users', 'App\Http\Controllers\UserController@index');
在大多數情況下,此更改不會影響到從舊版升級過來的專案,因為專案中的 RouteServiceProvider
內 $namespace
應該還是包含了原本的值。不過,如果你是通過建立新專案來升級 Laravel 的,此更改就可能變成中斷性變更。
若想繼續使用原本這種自動為 Controller 加上前置詞的 Route,只需要在 RouteServiceProvider
中為 $namespace
屬性設定適當的值,並在 boot
方法中將 Route 定義更新為使用 $namespace
屬性即可:
1class RouteServiceProvider extends ServiceProvider2{3 /**4 * The path to the "home" route for your application.5 *6 * This is used by Laravel authentication to redirect users after login.7 *8 * @var string9 */10 public const HOME = '/home';1112 /**13 * If specified, this namespace is automatically applied to your controller routes.14 *15 * In addition, it is set as the URL generator's root namespace.16 *17 * @var string18 */19 protected $namespace = 'App\Http\Controllers';2021 /**22 * Define your route model bindings, pattern filters, etc.23 *24 * @return void25 */26 public function boot()27 {28 $this->configureRateLimiting();2930 $this->routes(function () {31 Route::middleware('web')32 ->namespace($this->namespace)33 ->group(base_path('routes/web.php'));3435 Route::prefix('api')36 ->middleware('api')37 ->namespace($this->namespace)38 ->group(base_path('routes/api.php'));39 });40 }4142 /**43 * Configure the rate limiters for the application.44 *45 * @return void46 */47 protected function configureRateLimiting()48 {49 RateLimiter::for('api', function (Request $request) {50 return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());51 });52 }53}
1class RouteServiceProvider extends ServiceProvider2{3 /**4 * The path to the "home" route for your application.5 *6 * This is used by Laravel authentication to redirect users after login.7 *8 * @var string9 */10 public const HOME = '/home';1112 /**13 * If specified, this namespace is automatically applied to your controller routes.14 *15 * In addition, it is set as the URL generator's root namespace.16 *17 * @var string18 */19 protected $namespace = 'App\Http\Controllers';2021 /**22 * Define your route model bindings, pattern filters, etc.23 *24 * @return void25 */26 public function boot()27 {28 $this->configureRateLimiting();2930 $this->routes(function () {31 Route::middleware('web')32 ->namespace($this->namespace)33 ->group(base_path('routes/web.php'));3435 Route::prefix('api')36 ->middleware('api')37 ->namespace($this->namespace)38 ->group(base_path('routes/api.php'));39 });40 }4142 /**43 * Configure the rate limiters for the application.44 *45 * @return void46 */47 protected function configureRateLimiting()48 {49 RateLimiter::for('api', function (Request $request) {50 return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());51 });52 }53}
排程任務
cron-expression
函式庫
受影響的可能:低
Laravel 的相依性套件 dragonmantank/cron-expression
已從 2.x
版更新為 3.x
版。除非你有直接使用到 cron-expression
函式庫,否則這個更改應該不會造成任何中斷性變更。若你有直接使用到此函式庫,請閱讀其更新日誌。
Session
Session
Contract
受影響的可能:低
Illuminate\Contracts\Session\Session
Contract 現已定義了一個 pull
方法。若你有手動實作該 Contract,請更新該實作:
1/**2 * Get the value of a given key and then forget it.3 *4 * @param string $key5 * @param mixed $default6 * @return mixed7 */8public function pull($key, $default = null);
1/**2 * Get the value of a given key and then forget it.3 *4 * @param string $key5 * @param mixed $default6 * @return mixed7 */8public function pull($key, $default = null);
測試
decodeResponseJson
方法
受影響的可能:低
Illuminate\Testing\TestResponse
類別中的 decodeResponseJson
方法已不再接受任何引數。請考慮改用 json
方法。
assertExactJson
方法
受影響的可能性:中等
assertExactJson
方法現在要求以數字作為索引鍵來比較的陣列必須使用相同的順序。若想在不要求相同順序的情況下比較 JSON 與以數字作為索引鍵的陣列,請改用 assertSimilarJson
。
表單驗證
資料庫 Rule 的連線
受影響的可能:低
unique
與 exists
規則現在會在查詢時使用 Eloquent Model 所指定的連線名稱 (通過 Model 的 getConnectionName
方法取得)。
其他
我們也鼓勵你檢視 laravel/laravel
GitHub 存放庫上的更改。雖然這些更改中大多數都不是必須要進行的,但你可能也會想讓專案中的這些檔案保持同步。其中一些修改有在本升級指南中提到,但有些其他的更改(如設定檔的更改或註解等)就沒有提到。可以通過 GitHub 的比較工具來輕鬆地檢視這些更改,並自行評估哪些更改對你來說比較重要。