升級指南

高度影響的更改

中度影響的更改

從 8.x 升級到 9.0

預計升級所需時間:30 分鐘

lightbulb

雖然我們已經儘可能地在本說明文件中涵蓋所有中斷性變更(Breaking Change)。不過,在 Laravel 中,有些中斷性變更存在一些比較不明顯的地方,且這些更改中幾乎不太會影響到你的專案。 想節省時間嗎?可以使用 Laravel Shift 來協助你快速升級你的專案。

相依性套件更新

受影響的可能:高

最低版本要求為 PHP 8.0.2

Laravel 先已要求 PHP 最小版本為 8.0.2。

Composer 相依性套件

請在專案的 composer.json 檔案中更新下列相依性套件:

  • laravel/framework 升級為 ^9.0
  • nunomaduro/collision 升級為 ^6.1

此外,請在專案的 composer.json 檔中將 facade/ignition 改為 "spatie/laravel-ignition": "^1.0",並將 pusher/pusher-php-server (若有的話) 改為"pusher/pusher-php-server": "^5.0"

此外,下列第一方專案也有更新新的版本以支援 Laravel 9.x。若有使用這些套件,請在升級前先閱讀各套件的升級指南:

最後,請檢視你的專案使用的其他第三方套件,確認一下是否有使用支援 Laravel 9 的版本。

PHP Return 型別

對於一些如 offsetGetoffSet ⋯⋯等方法,PHP 已經開始進入一個要求回傳型別的過渡階段。因此,Laravel 9 也開始在程式碼中實作這些回傳型別。一般來說,應該是不會影響使用者的程式碼。不過,若你有複寫 Laravel 核心類別中的這些要求回傳型別的方法,則請在你的專案或套件程式碼中加上回傳型別:

  • count(): int
  • getIterator(): Traversable
  • getSize(): int
  • jsonSerialize(): array
  • offsetExists($key): bool
  • offsetGet($key): mixed
  • offsetSet($key, $value): void
  • offsetUnset($key): void

此外,PHP SessionHandlerInterface 的方法實作中也有新增回傳型別。一樣,通常這不會影響到你的專案或套件程式碼:

  • open($savePath, $sessionName): bool
  • close(): bool
  • read($sessionId): string|false
  • write($sessionId, $data): bool
  • destroy($sessionId): bool
  • gc($lifetime): int

Application

Application Contract

受影響的可能:低

Illuminate\Contracts\Foundation\Application 介面的 storagePath 方法已更新為接受一個 $path 引數。若你有實作這個介面,請更新該實作:

1public function storagePath($path = '');
1public function storagePath($path = '');

類似地,Illuminate\Foundation\Application 類別的 langPath 方法現在也更新為接受一個 $path 引數:

1public function langPath($path = '');
1public function langPath($path = '');

Exception Handler(例外處理常式)ignore 方法

受影響的可能:低

Exception Handler 的 ignore 方法現在已從 protected 改為 public。該方法不包含在預設的專案 Skeleton 內。不過,若你有手動定義這個方法,請將其可見度更改為 public

1public function ignore(string $class);
1public function ignore(string $class);

Exception Handler 的 Contract 繫結

受影響的可能:非常低

在之前版本的 Laravel 中,若要複寫 Laravel 預設的 Exception Handler,就必須使用 \App\Exceptions\Handler::class 型別來向 Service Container 繫結自定實作。不過,現在請改用 \Illuminate\Contracts\Debug\ExceptionHandler::class 型別來繫結自定實作。

Blade

Lazy Collection 與 $loop 變數

受影響的可能:低

在 Blade 樣板中迭代 LazyCollection 實體時,將不再提供 $loop 變數。因為存取 $loop 變數會讓整個 LazyCollection 都被載入進記憶體內,因此在這種情況下使用 Lazy Collection 來轉譯(Render)是沒意義的。

Checked / Disabled / Selected Blade 指示詞

受影響的可能:低

新的 @checked@disabled、與 @selected Blade 指示詞可能會擁有相同名稱的 Vue 事件衝突。可使用 @@ 來逸出這些指示詞,以避免衝突:@@selected

Collections

Enumerable Contract

受影響的可能:低

Illuminate\Support\Enumerable Contract 現在定義了一個 sole 方法。若你有手動實作這個介面,請更新你的實作以加上這個新方法:

1public function sole($key = null, $operator = null, $value = null);
1public function sole($key = null, $operator = null, $value = null);

reduceWithKeys 方法

reduceWithKeys 方法已被移除,因為 reduce 方法提供的功能與 reduceWithKeys 相同。只要將呼叫 reduceWithKeys 的程式碼改成呼叫 reduce 即可。

reduceMany 方法

reduceMany 方法已更名為 reduceSpread,以與其他類似方法維持命名的一貫性。

Container

Container Contract

受影響的可能:非常低

Illuminate\Contracts\Container\Container Contract 現在多了兩個方法定義:scopedscopedIf。若你有手動實作這個 Contract,請更新你的實作以加上這些新方法。

ContextualBindingBuilder Contract

受影響的可能:非常低

Illuminate\Contracts\Container\ContextualBindingBuilder Contract 現在定義了一個 giveConfig 方法。若你有手動實作這個方法,請更新你的實作以反應這個新方法:

1public function giveConfig($key, $default = null);
1public function giveConfig($key, $default = null);

資料庫

Postgres 的「Schema」設定

受影響的可能性:中等

config/database.php 設定檔中,用來設定 Postgress 連線搜尋路徑的 schema 設定選項已改名為 search_path

Schema Builder registerCustomDoctrineType 方法

受影響的可能:低

registerCustomDoctrineType 方法已從 Illuminate\Database\Schema\Builder 類別內移除。可使用 DB Facade 上的 registerDoctrineType 方法來代替,或是在 config/database.php 設定檔內註冊自訂的 Doctrine 型別。

Eloquent

自訂 Cast 與 null

受影響的可能性:中等

在之前版本的 Laravel中,在將 Cast 屬性設為 null 時不會叫用自訂 Cast 類別的 set 方法。不過,這個行為與 Laravel 說明文件中的不一致,因此在 Laravel 9.x 中,會叫用 Cast 類別的 set 方法,並提供 null 作為 $value 引數。因此,請確保你的自訂 Cast 可處理這類狀況:

1/**
2 * Prepare the given value for storage.
3 *
4 * @param \Illuminate\Database\Eloquent\Model $model
5 * @param string $key
6 * @param AddressModel $value
7 * @param array $attributes
8 * @return array
9 */
10public function set($model, $key, $value, $attributes)
11{
12 if (! $value instanceof AddressModel) {
13 throw new InvalidArgumentException('The given value is not an Address instance.');
14 }
15 
16 return [
17 'address_line_one' => $value->lineOne,
18 'address_line_two' => $value->lineTwo,
19 ];
20}
1/**
2 * Prepare the given value for storage.
3 *
4 * @param \Illuminate\Database\Eloquent\Model $model
5 * @param string $key
6 * @param AddressModel $value
7 * @param array $attributes
8 * @return array
9 */
10public function set($model, $key, $value, $attributes)
11{
12 if (! $value instanceof AddressModel) {
13 throw new InvalidArgumentException('The given value is not an Address instance.');
14 }
15 
16 return [
17 'address_line_one' => $value->lineOne,
18 'address_line_two' => $value->lineTwo,
19 ];
20}

Belongs To Many firstOrNewfirstOrCreateupdateOrCreate 方法

受影響的可能性:中等

belongsToMany 關聯的 firstOrNewfirstOrCreateupdateOrCreate 等方法都接受傳入一組屬性陣列作為第一個引數。在之前版本的 Laravel 中,這組屬性變數會先與「Pivot(樞紐)」/中介資料表上現有的紀錄做比較。

不過,由於這個行為是未預期的,且一般來說我們不會想要這個行為。因此,現在這幾個方法已改為以 Model 上對應的資料表來跟屬性陣列做比較:

1$user->roles()->updateOrCreate([
2 'name' => 'Administrator',
3]);
1$user->roles()->updateOrCreate([
2 'name' => 'Administrator',
3]);

此外,firstOrCreate 方法現已接受一個 $values 陣列作為其第二個引數。建立關聯 Model 時若還未有關聯 Model,會將這個陣列與該方法的第一個引數 ($attributes) 合併。這個更改即讓該方法與其他關聯型別上提供的 firstOrCreate 保持一致:

1$user->roles()->firstOrCreate([
2 'name' => 'Administrator',
3], [
4 'created_by' => $user->id,
5]);
1$user->roles()->firstOrCreate([
2 'name' => 'Administrator',
3], [
4 'created_by' => $user->id,
5]);

touch 方法

受影響的可能:低

touch 方法現已接受一個要被 Touch 的屬性。若你之前有複寫這個方法,請更新方法簽章(Signature)以反應出此引數:

1public function touch($attribute = null);
1public function touch($attribute = null);

Encryption

Encrypter Contract

受影響的可能:低

Illuminate\Contracts\Encryption\Encrypter Contract 現已定義了一個 getKey 方法。若你有手動實作該介面,請更新該實作:

1public function getKey();
1public function getKey();

Facade

getFacadeAccessor 方法

受影響的可能:低

getFacadeAccessor 方法只能回傳 Container 的繫結索引鍵(Binding Key)。在之前版本的 Laravel 中,這個方法可以回傳物件實體。不過,現在已不支援這個行為。若你有自行撰寫 Facade,請確保該方法回傳的是 Container 的繫結索引鍵字串:

1/**
2 * Get the registered name of the component.
3 *
4 * @return string
5 */
6protected static function getFacadeAccessor()
7{
8 return Example::class;
9}
1/**
2 * Get the registered name of the component.
3 *
4 * @return string
5 */
6protected static function getFacadeAccessor()
7{
8 return Example::class;
9}

Filesystem

FILESYSTEM_DRIVER 環境變數

受影響的可能:低

FILESYSTEM_DRIVER 環境變數已改名為 FILESYSTEM_DISK,以更確切反映出其用途。該更改只會影響專案 Skeleton。不過,若你想要的話,也歡迎你更新你專案上的環境變數以反映此更改。

「Cloud」Disk

受影響的可能:低

從 2020 年 11 月起,cloud Disk 設定選項已自預設的專案 Skeleton 中移除。這個更改只影響專案 Skeleton。若你有在專案中使用 cloud Disk,可在你自己的專案 Skeleton 中保留此設定值。

Flysystem 3.x

受影響的可能:高

Laravel 9.x 以從 Flysystem 1.x 更新為 3.x。Flysystem 在幕後驅動了 Storage Facade 的所有檔案處理方法。有鑑於此,有可能會需要你修改你的專案中的一些地方。不過,我們已盡量讓這些修改變得容易。

Driver 前置需求

在使用 S3、FTP、SFTP 等 Driver 時,需要使用 Composer 套件管理員安裝適當的套件:

  • Amazon S3: composer require -W league/flysystem-aws-s3-v3 "^3.0"
  • FTP: composer require league/flysystem-ftp "^3.0"
  • SFTP: composer require league/flysystem-sftp-v3 "^3.0"

覆寫已存在的檔案

putwrite、與 writeStream 等寫入操作現在會預設覆蓋現有的檔案。若不想複寫現有的檔案,請在執行寫入動作前先確認檔案是否存在。

寫入 Exception

putwrite、與 writeStream 等的寫入操作現在已不會在寫入操作失敗時擲回 Exception,而會回傳 false。若想保留此一擲回 Exception 的行為,可在 filesystem 的 disk 設定陣列中定義 throw 選項:

1'public' => [
2 'driver' => 'local',
3 // ...
4 'throw' => true,
5],
1'public' => [
2 'driver' => 'local',
3 // ...
4 'throw' => true,
5],

讀取不存在的檔案

若嘗試讀取不存在的檔案,現在會回傳 null。在之前版本的 Laravel 中,會擲回(Throw) Illuminate\Contracts\Filesystem\FileNotFoundException

刪除不存在的檔案

嘗試使用 delete 刪除不存在的檔案時,現在會回傳 true

Cached Adapter

Flysystem 現在不支援「Cached Adapter」了。因此,Laravel 中已移除這些 Adapter,你可以移除一些與其相關的設定 (如 Disk 設定中的 cache 索引鍵等)。

自訂 Filesystem

要註冊自訂 Filesystem Driver 所需的步驟有一些小更改。因此,若你有定義你自己的自訂 Filesystem Driver,或是使用有定義自訂 Driver 的套件,請更新你的程式碼或相依性套件。

舉例來說,Laravel 8.x 中,可以像這樣註冊 Filesystem Driver:

1use Illuminate\Support\Facades\Storage;
2use League\Flysystem\Filesystem;
3use Spatie\Dropbox\Client as DropboxClient;
4use Spatie\FlysystemDropbox\DropboxAdapter;
5 
6Storage::extend('dropbox', function ($app, $config) {
7 $client = new DropboxClient(
8 $config['authorization_token']
9 );
10 
11 return new Filesystem(new DropboxAdapter($client));
12});
1use Illuminate\Support\Facades\Storage;
2use League\Flysystem\Filesystem;
3use Spatie\Dropbox\Client as DropboxClient;
4use Spatie\FlysystemDropbox\DropboxAdapter;
5 
6Storage::extend('dropbox', function ($app, $config) {
7 $client = new DropboxClient(
8 $config['authorization_token']
9 );
10 
11 return new Filesystem(new DropboxAdapter($client));
12});

不過,在 Laravel 9.x 中,傳給 Storage::extend 方法的回呼應直接回傳一個 Illuminate\Filesystem\FilesystemAdapter 的實體:

1use Illuminate\Filesystem\FilesystemAdapter;
2use Illuminate\Support\Facades\Storage;
3use League\Flysystem\Filesystem;
4use Spatie\Dropbox\Client as DropboxClient;
5use Spatie\FlysystemDropbox\DropboxAdapter;
6 
7Storage::extend('dropbox', function ($app, $config) {
8 $adapter = new DropboxAdapter(
9 new DropboxClient($config['authorization_token'])
10 );
11 
12 return new FilesystemAdapter(
13 new Filesystem($adapter, $config),
14 $adapter,
15 $config
16 );
17});
1use Illuminate\Filesystem\FilesystemAdapter;
2use Illuminate\Support\Facades\Storage;
3use League\Flysystem\Filesystem;
4use Spatie\Dropbox\Client as DropboxClient;
5use Spatie\FlysystemDropbox\DropboxAdapter;
6 
7Storage::extend('dropbox', function ($app, $config) {
8 $adapter = new DropboxAdapter(
9 new DropboxClient($config['authorization_token'])
10 );
11 
12 return new FilesystemAdapter(
13 new Filesystem($adapter, $config),
14 $adapter,
15 $config
16 );
17});

輔助函式

data_get 輔助函式與 Iterable 的物件

受影響的可能:非常低

之前,data_get 輔助函式可用來在陣列與 Collection 實體上取得巢狀資料。不過,data_get 現在已可在所有 Iterable 的物件上取得巢狀資料了。

str 輔助函式

受影響的可能:非常低

Laravel 9.x 現在包含了一個全域的 str 輔助函式。若你有在專案中定義全域的 str 輔助函式,請重新命名或移除該函式以避免與 Laravel 的 str 輔助函式衝突。

when / unless 方法

受影響的可能性:中等

讀者可能已經知道,在 Laravel 中有許多類別都提供了 whenunless 方法。可以使用這些方法來依據提供給該方法之第一個引數的布林值是 true 還是 false 來有條件地進行一些動作:

1$collection->when(true, function ($collection) {
2 $collection->merge([1, 2, 3]);
3});
1$collection->when(true, function ($collection) {
2 $collection->merge([1, 2, 3]);
3});

因此,在之前版本的 Laravel 中,若傳遞閉包給 whenunless 方法,則一定會執行給定的條件式動作,因為在對閉包物件 (或其他物件) 做鬆散比較時,結果一定會是 true。通常來說這會導致一些未預期的結果,因為開發人員通常會預期使用閉包的 結果 來作為判斷是否執行條件式動作的布林值。

因此,在 Laravel 9.x 中,傳給 whenunless 方法的閉包會被執行,而該閉包回傳的值會被用來當作 whenunless 方法要判斷的布林值:

1$collection->when(function ($collection) {
2 // 會執行這個閉包...
3 return false;
4}, function ($collection) {
5 // 因為第一個閉包回傳「false」,因此不會執行這個閉包...
6 $collection->merge([1, 2, 3]);
7});
1$collection->when(function ($collection) {
2 // 會執行這個閉包...
3 return false;
4}, function ($collection) {
5 // 因為第一個閉包回傳「false」,因此不會執行這個閉包...
6 $collection->merge([1, 2, 3]);
7});

HTTP 用戶端

預設的逾時

受影響的可能性:中等

HTTP 用戶端 現在的預設逾時設定為 30 秒。換句話說,若伺服器在 30 秒內未回應,會擲回(Throw)一個 Exception。以前,HTTP 用戶端上並沒有設定逾時,因此有時候 Request 可能會無限地「當掉」。

若想為給定 Request 指定更長的逾時設定,可使用 timeout 方法:

1$response = Http::timeout(120)->get(/* ... */);
1$response = Http::timeout(120)->get(/* ... */);

HTTP Fake 與 Middleware

受影響的可能:低

之前,若使用「假的(Fake)HTTP 用戶端,Laravel 就不會執行任何提供的 Guzzle HTTP Middleware。不過,在 Laravel 9.x 中,就算有 Fake HTTP 用戶端,還是會執行 Guzzle HTTP Middleware。

HTTP Fake 與相依性插入

受影響的可能:低

在之前版本的 Laravel 中,叫用 Http::fake() 方法不會影響到插入到類別 Constructor(建構函式) 上的 Illuminate\Http\Client\Factory 實體。不過,在 Laravel 9.x 中,Http::fake() 會確保使用相依性插入所插入到其他類別的 HTTP 用戶端回傳的是 Fake 過的 Response。這個行為也讓 Http::fake() 與其他 Facade、Fake 更一致。

Symfony Mailer

受影響的可能:高

Laravel 9.x 中,其中一個最大的更改就是將 SwiftMailer 更改為 Symfony Mailer。自從 2021 年 12 月起,SwiftMailer 就不再維護了。不過,我們儘量讓你在專案中可以無縫將 SwiftMailer 改為 Symfony Mailer。因此,請檢視下列更改,以確保你的專案有完整支援 Symfony Mailer。

Driver 前置需求

若要繼續使用 Mailgun Transport,請在專案中 Require symfony/mailgun-mailersymfony/http-client Composer 套件:

1composer require symfony/mailgun-mailer symfony/http-client
1composer require symfony/mailgun-mailer symfony/http-client

請從專案中移除 wildbit/swiftmailer-postmark Composer 套件,並改 Require symfony/postmark-mailersymfony/http-client Composer 套件:

1composer require symfony/postmark-mailer symfony/http-client
1composer require symfony/postmark-mailer symfony/http-client

回傳型別的更新

Illuminate\Mail\Mailersendhtmlrawplain 等方法將不再回傳 void,而是回傳一個 Illuminate\Mail\SentMessage 實體。這個物件中包含了一個 Symfony\Component\Mailer\SentMessage 實體,可以通過 getSymfonySentMessage 方法來取得該實體,或是在該物件上動態呼叫方法:

「Swift」方法的更名

有多個與 SwiftMailer 相關的方法都已改名為與 Symfony Mailer 相應的名稱,其中有些是未包含在說明文件內的。舉例來說,withSwiftMessage 方法已更名為 withSymfonyMessage

1// Laravel 8.x...
2$this->withSwiftMessage(function ($message) {
3 $message->getHeaders()->addTextHeader(
4 'Custom-Header', 'Header Value'
5 );
6});
7 
8// Laravel 9.x...
9use Symfony\Component\Mime\Email;
10 
11$this->withSymfonyMessage(function (Email $message) {
12 $message->getHeaders()->addTextHeader(
13 'Custom-Header', 'Header Value'
14 );
15});
1// Laravel 8.x...
2$this->withSwiftMessage(function ($message) {
3 $message->getHeaders()->addTextHeader(
4 'Custom-Header', 'Header Value'
5 );
6});
7 
8// Laravel 9.x...
9use Symfony\Component\Mime\Email;
10 
11$this->withSymfonyMessage(function (Email $message) {
12 $message->getHeaders()->addTextHeader(
13 'Custom-Header', 'Header Value'
14 );
15});
exclamation

請稍微檢視一下 Symfony Mailer 說明文件以瞭解所有使用 Symfony\Component\Mime\Email 物件的方法。

下面詳細列出了針對這些改名過的方法。其中許多方法都是用來直接使用 SwiftMailer / Symfony Mailer 的低階方法,所以在大多數 Laravel 專案中並不常用:

1Message::getSwiftMessage();
2Message::getSymfonyMessage();
3 
4Mailable::withSwiftMessage($callback);
5Mailable::withSymfonyMessage($callback);
6 
7MailMessage::withSwiftMessage($callback);
8MailMessage::withSymfonyMessage($callback);
9 
10Mailer::getSwiftMailer();
11Mailer::getSymfonyTransport();
12 
13Mailer::setSwiftMailer($swift);
14Mailer::setSymfonyTransport(TransportInterface $transport);
15 
16MailManager::createTransport($config);
17MailManager::createSymfonyTransport($config);
1Message::getSwiftMessage();
2Message::getSymfonyMessage();
3 
4Mailable::withSwiftMessage($callback);
5Mailable::withSymfonyMessage($callback);
6 
7MailMessage::withSwiftMessage($callback);
8MailMessage::withSymfonyMessage($callback);
9 
10Mailer::getSwiftMailer();
11Mailer::getSymfonyTransport();
12 
13Mailer::setSwiftMailer($swift);
14Mailer::setSymfonyTransport(TransportInterface $transport);
15 
16MailManager::createTransport($config);
17MailManager::createSymfonyTransport($config);

經過代理的 Illuminate\Mail\Message 方法

Illuminate\Mail\Message 一般來說都會將不存在的方法代理到底層的 Swift_Message 實體上。不過,現在,不存在的方法會改為代理到 Symfony\Component\Mime\Email 實體上。因此,若先前有任何仰賴這個將不存在方法代理到 SwiftMailer 的程式碼都應改為使用其在 Symfony Mailer 中相應的部分。

同樣的,許多專案應該都不會使用到這些方法,因為這些方法並沒有寫在 Laravel 說明文件中:

1// Laravel 8.x...
2$message
3 ->setFrom('[email protected]')
4 ->setTo('[email protected]')
5 ->setSubject('Order Shipped')
6 ->setBody('<h1>HTML</h1>', 'text/html')
7 ->addPart('Plain Text', 'text/plain');
8 
9// Laravel 9.x...
10$message
11 ->from('[email protected]')
13 ->subject('Order Shipped')
14 ->html('<h1>HTML</h1>')
15 ->text('Plain Text');
1// Laravel 8.x...
2$message
3 ->setFrom('[email protected]')
4 ->setTo('[email protected]')
5 ->setSubject('Order Shipped')
6 ->setBody('<h1>HTML</h1>', 'text/html')
7 ->addPart('Plain Text', 'text/plain');
8 
9// Laravel 9.x...
10$message
11 ->from('[email protected]')
13 ->subject('Order Shipped')
14 ->html('<h1>HTML</h1>')
15 ->text('Plain Text');

產生的 Message ID

SwiftMailer 提供了可使用 mime.idgenerator.idright 設定選項來定義要包含在產生之 Message ID 中的自訂網域。Symfony Mailer 不支援這個功能。Symfony Mailer 只會依據寄件人自動產生 Message ID。

MessageSent Event 的更改

Illuminate\Mail\Events\MessageSent 事件的 message 屬性現在已不再包含 Swift_Message 實體,而改為 Symfony\Component\Mime\Email 實體。此訊息表示了 E-Mail 寄出前 的狀態。

此外,MessageSent 事件中也加上了一個新的 sent 屬性。此屬性包含了 Illuminate\Mail\SentMessage 實體,其中有已寄出 E-Mail 的資訊,如 Message ID。

強制重新連線

現在已經無法再強制 Transport 重新連線了 (如使用 Daemon 處理程序執行 Mailer 時)。Symfony Mailer 會自動嘗試重新連線,並在重新連線失敗時擲回(Throw) Exception。

SMTP 串流選項

現在已不支援為 SMTP Transport 定義串流選項。若有支援相應的選項,請改為定義這些選項。舉例來說,若要禁用 TLS Peer Verification:

1'smtp' => [
2 // Laravel 8.x...
3 'stream' => [
4 'ssl' => [
5 'verify_peer' => false,
6 ],
7 ],
8 
9 // Laravel 9.x...
10 'verify_peer' => false,
11],
1'smtp' => [
2 // Laravel 8.x...
3 'stream' => [
4 'ssl' => [
5 'verify_peer' => false,
6 ],
7 ],
8 
9 // Laravel 9.x...
10 'verify_peer' => false,
11],

若要瞭解更多可用的選項,請參考 Symfony Mailer 說明文件

exclamation

雖然有上述這樣的範例,但一般來說建議不要禁用 SSL 驗證,因為有可能會導致「中間人(man-in-the-middle, MITM)」攻擊

SMTP auth_mode

現在已不支援在 mail 設定中定義 SMTP 的 auth_mode。Symfony Mailer 會自動與 SMTP 伺服器取得認證方法。

寄送失敗的收件人

送出訊息後,現在已無法取得無法寄出的收件人列表。若訊息送出失敗,現在只會擲回(Throw)一個 Symfony\Component\Mailer\Exception\TransportExceptionInterface Exception。我們建議你不要在送出訊息後去取得無效的 E-Mail 位址,而是在送出訊息前就驗證 E-Mail 位址。

套件

lang 目錄

受影響的可能性:中等

在新的 Laravel 專案中,resources/lang 目錄現在改放在專案根目錄了 (lang)。若你的專案有將語系檔安裝到這個資料夾,請確保是使用 app()->langPath() 來安裝,而不是使用硬式編碼(Hard-Coded)的路徑。

佇列

opis/closure 套件

受影響的可能:低

Laravel 的 opis/closure 相依性套件現已改為 laravel/serializable-closure。這應該不會對你的程式造成任何的破壞性變更(Breaking Change),除非你有直接使用到 opis/closure 套件。此外,現已移除之前已棄用(Deprecated)Illuminate\Queue\SerializableClosureFactoryIlluminate\Queue\SerializableClosure。若你有直接使用到 opis/closure 函式庫,或是有使用到任何已移除的類別,可使用 Laravel Serializable Closure 來代替。

Failed Job Provider 的 flush 方法

受影響的可能:低

Illuminate\Queue\Failed\FailedJobProviderInterface 介面中定義的 flush 方法現已支援一個 $hours 引數。使用該引數可用來判斷執行失敗的任務在被 queue:flush 指令清除前必須要保留多久 (單位:小時)。若你有手動實作 FailedJobProviderInterface,請確保有更新該實作以反映這個新引數:

1public function flush($hours = null);
1public function flush($hours = null);

Session

getSession 方法

受影響的可能:低

Laravel 的 Illuminate\Http\Request 類別所繼承的 Symfony\Component\HttpFoundaton\Request 類別現已提供了一個 getSession 方法,可用來取得目前的 Session Storage Handler(存放空間處理常式)。Laravel 說明文件中並未提及該方法,因為大多數的 Laravel 專案都使用 Laravel 自己的 session 方法來處理 Session。

之前,getSession 方法會回傳 Illuminate\Session\Store 實體或 null。不過,由於 Symfony 6.x 版本強制回傳型別為 Symfony\Component\HttpFoundation\Session\SessionInterface,因此 getSession 現在會回傳一個 SessionInterface 實作,或是當沒有可用的 Session 時會擲回(Throw) \Symfony\Component\HttpFoundation\Exception\SessionNotFoundException Exception。

測試

assertDeleted 方法

受影響的可能性:中等

assertDeleted 方法的呼叫應更改為 assertModelMissing

Trusted Proxies

受影響的可能:低

若你是通過將現有程式碼複製到新安裝的 Laravel 9 應用程式 Skeletong 中來從 Laravel 8 升級到 Laravel 9 的話,需要更新專案的「Trusted Proxy」Middleware。

app/Http/Middleware/TrustProxies.php 檔案中,請將 use Fideloper\Proxy\TrustProxies as Middleware 更新為 use Illuminate\Http\Middleware\TrustProxies as Middleware

接著,在 app/Http/Middleware/TrustProxies.php 中,請更新 $headers 屬性的定義:

1// 舊的...
2protected $headers = Request::HEADER_X_FORWARDED_ALL;
3 
4// 新的...
5protected $headers =
6 Request::HEADER_X_FORWARDED_FOR |
7 Request::HEADER_X_FORWARDED_HOST |
8 Request::HEADER_X_FORWARDED_PORT |
9 Request::HEADER_X_FORWARDED_PROTO |
10 Request::HEADER_X_FORWARDED_AWS_ELB;
1// 舊的...
2protected $headers = Request::HEADER_X_FORWARDED_ALL;
3 
4// 新的...
5protected $headers =
6 Request::HEADER_X_FORWARDED_FOR |
7 Request::HEADER_X_FORWARDED_HOST |
8 Request::HEADER_X_FORWARDED_PORT |
9 Request::HEADER_X_FORWARDED_PROTO |
10 Request::HEADER_X_FORWARDED_AWS_ELB;

最後,請從專案中移除 fideloper/proxy Composer 相依性套件:

1composer remove fideloper/proxy
1composer remove fideloper/proxy

表單驗證

Form Request 的 validated 方法

受影響的可能:低

Form Request 提供的 validated 方法現已接受 $key$default 兩個引數。若有手動複寫該方法的定義,請更新方法簽章(Signature)以反映這些新引數:

1public function validated($key = null, $default = null)
1public function validated($key = null, $default = null)

password 規則

受影響的可能性:中等

用來驗證給定輸入值是否符合已登入使用者目前密碼的 password 規則,現已更名為 current_password

未驗證的陣列索引鍵

受影響的可能性:中等

在之前版本的 Laravel 中,我們可能會需要手動讓 Laravel 的 Validator 從「已驗證(Validated)」資料中排除一些未驗證的陣列索引鍵。特別是當我們在使用 array 規則時未指定允許的索引鍵時。

不過,在 Laravel 9.x 中,未驗證的陣列索引鍵一定會被從「已驗證」陣列中排除。就算在 array 規則上未指定允許的索引鍵也一樣。一般來說,這是我們最直覺會預期的行為。而之前在 Laravel 8.x 中加上的 excludeUnvalidatedArrayKeys 方法只是一個用來保持向下相容性的臨時方案。

雖然我們不建議,但你可以在專案中任何一個 Service Provider 的 boot 方法內叫用 includeUnvalidatedArrayKeys 方法來使用以前 Laravel 8.x 的行為:

1use Illuminate\Support\Facades\Validator;
2 
3/**
4 * Register any application services.
5 *
6 * @return void
7 */
8public function boot()
9{
10 Validator::includeUnvalidatedArrayKeys();
11}
1use Illuminate\Support\Facades\Validator;
2 
3/**
4 * Register any application services.
5 *
6 * @return void
7 */
8public function boot()
9{
10 Validator::includeUnvalidatedArrayKeys();
11}

其他

我們也鼓勵你檢視 laravel/laravel GitHub 存放庫上的更改。雖然這些更改中大多數都不是必須要進行的,但你可能也會想讓專案中的這些檔案保持同步。其中一些修改有在本升級指南中提到,但有些其他的更改(如設定檔的更改或註解等)就沒有提到。可以通過 GitHub 的比較工具來輕鬆地檢視這些更改,並自行評估哪些更改對你來說比較重要。

翻譯進度
100% 已翻譯
更新時間:
2023年2月11日 下午12:59:00 [世界標準時間]
翻譯人員:
  • cornch
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.