我正在 Symfony 6 應用程式中試驗 PHP 列舉,我認為我找到了一個非常好的用例。一切正常,但 phpstan 一直抱怨我回傳的型別。
------ -----------------------------------------------------------------------------------------------------------------------------------------------
Line src/Entity/User.php
------ -----------------------------------------------------------------------------------------------------------------------------------------------
93 Return type (array<App\Security\Roles>) of method App\Entity\User::getRoles() should be compatible with return type (array<string>) of method
Symfony\Component\Security\Core\User\UserInterface::getRoles()
------ -----------------------------------------------------------------------------------------------------------------------------------------------
我的列舉看起來像這樣:
namespace App\Security;
enum Roles: string
{
case Admin = 'ROLE_ADMIN';
case User = 'ROLE_USER';
}
在我User實作的物體中Symfony\Component\Security\Core\User\UserInterface,我有這個:
/**
* @see UserInterface
* @return array<Roles>
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = Roles::User->value;
return array_unique($roles);
}
/**
* @param array<Roles> $roles
*/
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
我知道 phpstan 期望陣列包含介面中定義的字串,
/**
* @return string[]
*/
public function getRoles(): array;
但是有沒有辦法解決這個問題?我真的更希望能夠利用列舉。向列舉添加型別的目的不是能夠將其用作該型別嗎?另外值得一提的是,我在任何地方都使用嚴格的型別,除了 phpstan 對我的型別不太滿意之外,一切正常。
uj5u.com熱心網友回復:
您的回傳注釋是錯誤的,因為 PhpStan 正在正確報告。
您說您報告了一系列角色:
/**
* @return array<Roles>
*/
如果是這種情況,roles將直接包含一個列舉,而不是支持的列舉的值:
$this->roles[] = Roles::Admin
通過保留錯誤的注釋,您不僅會惹惱 PhpStan,而且還會將錯誤的資訊提供給getRoles(). 您擁有的注釋意味著我應該能夠做到:
/** @var <array>Roles */
$roles = $user->getRoles();
foreach ($roles as $role) {
if ($role === Roles::Admin) {
// something
}
}
但是您實際上是在回傳string[],而不是Roles[],因此我的代碼將無法正常作業,并且我的應用程式將崩潰。悲傷遍及大地。
如果沒有看到額外的代碼,看起來你并沒有真正以不同于類常量的方式“使用列舉”。roles不是 的集合Roles,您的addRole()方法將采用 a string,而不是 aRoles等。
當然,這很好。由于您需要遵守 ,因此UserInterface帶有一些常量的類可能更適合這里。
/**
* @return array<Roles::ROLE_*>
*/
這個注釋作業的一個天真的例子是:
<?php declare(strict_types = 1);
abstract class Roles {
const ROLE_FOO = 'foo';
const ROLE_BAR = 'bar';
const ROLE_BAZ = 'baz';
}
/**
* @param array<Roles::*> $s
*/
function sayHello(array $s): void
{
foreach ($s as $si) {
echo 'Hello, ' . $si, "\n";
}
}
$array = [
Roles::ROLE_FOO,
Roles::ROLE_BAR
];
sayHello($array);
$badArray = [
Roles::ROLE_FOO,
'some'
];
// this is an error!
sayHello($badArray);
(游樂場鏈接)
如果你想為你的角色使用列舉,那么實際使用它們。但是您將無法直接使用它們, getRoles()因為它會破壞界面。
You could have a companion set of methods (getRealRoles(), addRealRole(Roles $role), etc), wich would deal with the roles property, and you'd leave getRoles() simply to convert the array<Roles> into an array<string>.
No, you wouldn't be able to express "getRoles returns an array comprised of elments that are the possible backed values of the Roles enum", but it's fine, because in your (as opposed to framework code, which does not care about your implementation) code you would use the methods that work with the enums.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/444182.html
下一篇:CKEditor配置“微”不存在
