PHP 键入 return 混合内容
PHP typed return mixed content
我已经开始将我的代码转换为类型 properties/typed 函数 returns,这是一种很好的做法。但我对混合内容有疑问。
我知道 return 混合内容通常不是一个好的做法,但我有一种情况是不可避免的。我有一个 class 用作数据容器(它具有多种功能,但我将跳到基础知识):
class Container {
private array $list = [];
public set(string $key, ?? $value): void {
$this->list[$key] = $value;
}
public get(string $key): ?? {
return $this->list[$key];
}
}
我跳过了所有检查和所有其他功能。关键是 list
可以容纳 any 类型的东西(整数、布尔值、字符串、其他 class 对象......)所以我应该如何处理这个?
我知道 PHP 8 会有 union return 类型所以至少我可以缩小它的范围 (int|float|string...) 但因为这是很新的我不知道该怎么办。
保持简短。你不能用 PHP7 做到这一点。正如您已经说过的,联合类型声明将在 PHP8 中可用,当天尚未发布。
另一种方法是为您正在使用的每种类型编写 collections。您可以使用接口来识别类型。在一个完美的世界中,一切都是 object,如下例所示。
首先是 collections.
<?php
declare(strict_types=1);
namespace YourApp\Model;
use InvalidArgumentException;
use SplObjectStorage;
class TeamCollection extends SplObjectStorage
{
public function attach(object $object, $data = null): void
{
if ($object instanceof Team) {
throw new InvalidArgumentException(sprintf(
'The given object is not a team. %s given.',
get_class($object)
));
}
parent::attach($object, $data);
}
}
这是 collection 团队 classes 的。它只接受 Team classes 附加一些东西到这个 collection 上。否则会抛出异常。由于继承,您不能向团队键入 object 提示,因为这会引发另一个错误。 SplObjectCollection class 将 $object
参数定义为 object 类型。你不能覆盖它。因此,如果给定团队 class,我们可以检查附加方法。
<?php
declare(strict_types=1);
namespace YourApp\Model;
use YourApp\Model\TeamMemberCollection;
use YourApp\Model\TeamMember;
interface Team
{
public function getName(): ?string;
public function setName(string $name): self;
public function addMember(TeamMember $member): self
public function getMembers(): TeamMemberCollection;
}
该接口定义了我们团队所需的方法。现在我们可以写一个 Team class.
<?php
declare(strict_types=1);
namespace YourApp\Model;
class SoccerTeam implements Team
{
protected TeamMemberCollection $members;
protected string $name;
public function __construct()
{
$this->members = new TeamMemberCollection();
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function addTeamMember(TeamMember $member): self
{
$this->members->attach($member);
return $this;
}
public function getMembers(): TeamMemberCollection
{
return $this->members;
}
}
这个团队class的例子可以转移到TeamMember class。原则上,它会完全像这样。
现在让我们来看看我们的团队 collection 及其运作方式。
$teams = new TeamCollection();
$team = (new SoccerTeam())
->setName('Borussia Dortmund');
$teams->attach($team);
这是一个正面的例子。由于 SoccerTeam class 实现了 Team 接口,因此它会被球队 collection 接受。 collection 本身检查是否附加了 Team 实例。任何其他情况都会导致异常。
我已经开始将我的代码转换为类型 properties/typed 函数 returns,这是一种很好的做法。但我对混合内容有疑问。
我知道 return 混合内容通常不是一个好的做法,但我有一种情况是不可避免的。我有一个 class 用作数据容器(它具有多种功能,但我将跳到基础知识):
class Container {
private array $list = [];
public set(string $key, ?? $value): void {
$this->list[$key] = $value;
}
public get(string $key): ?? {
return $this->list[$key];
}
}
我跳过了所有检查和所有其他功能。关键是 list
可以容纳 any 类型的东西(整数、布尔值、字符串、其他 class 对象......)所以我应该如何处理这个?
我知道 PHP 8 会有 union return 类型所以至少我可以缩小它的范围 (int|float|string...) 但因为这是很新的我不知道该怎么办。
保持简短。你不能用 PHP7 做到这一点。正如您已经说过的,联合类型声明将在 PHP8 中可用,当天尚未发布。
另一种方法是为您正在使用的每种类型编写 collections。您可以使用接口来识别类型。在一个完美的世界中,一切都是 object,如下例所示。
首先是 collections.
<?php
declare(strict_types=1);
namespace YourApp\Model;
use InvalidArgumentException;
use SplObjectStorage;
class TeamCollection extends SplObjectStorage
{
public function attach(object $object, $data = null): void
{
if ($object instanceof Team) {
throw new InvalidArgumentException(sprintf(
'The given object is not a team. %s given.',
get_class($object)
));
}
parent::attach($object, $data);
}
}
这是 collection 团队 classes 的。它只接受 Team classes 附加一些东西到这个 collection 上。否则会抛出异常。由于继承,您不能向团队键入 object 提示,因为这会引发另一个错误。 SplObjectCollection class 将 $object
参数定义为 object 类型。你不能覆盖它。因此,如果给定团队 class,我们可以检查附加方法。
<?php
declare(strict_types=1);
namespace YourApp\Model;
use YourApp\Model\TeamMemberCollection;
use YourApp\Model\TeamMember;
interface Team
{
public function getName(): ?string;
public function setName(string $name): self;
public function addMember(TeamMember $member): self
public function getMembers(): TeamMemberCollection;
}
该接口定义了我们团队所需的方法。现在我们可以写一个 Team class.
<?php
declare(strict_types=1);
namespace YourApp\Model;
class SoccerTeam implements Team
{
protected TeamMemberCollection $members;
protected string $name;
public function __construct()
{
$this->members = new TeamMemberCollection();
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function addTeamMember(TeamMember $member): self
{
$this->members->attach($member);
return $this;
}
public function getMembers(): TeamMemberCollection
{
return $this->members;
}
}
这个团队class的例子可以转移到TeamMember class。原则上,它会完全像这样。
现在让我们来看看我们的团队 collection 及其运作方式。
$teams = new TeamCollection();
$team = (new SoccerTeam())
->setName('Borussia Dortmund');
$teams->attach($team);
这是一个正面的例子。由于 SoccerTeam class 实现了 Team 接口,因此它会被球队 collection 接受。 collection 本身检查是否附加了 Team 实例。任何其他情况都会导致异常。