首页 >后端开发 >php教程 >在PHP中创建严格键入的数组和收集

在PHP中创建严格键入的数组和收集

Christopher Nolan
Christopher Nolan原创
2025-02-10 11:20:11134浏览

在PHP中创建严格键入的数组和收集

钥匙要点

    php 5.6引入了使用…代币创建键入数组的能力,该功能或方法表示函数或方法接受可变的参数长度。可以将此功能与类型提示结合在一起,以确保仅在数组中接受某些类型的对象。
  • >此功能的一个限制是,每个方法只能定义一个键入的数组。为了克服这一点,可以将键入的数组注入“集合”类中,这也允许比Get Methods上的“数组”更具体的返回类型。
  • 值对象可用于自定义验证。例如,可以使用约束来创建一个评分值对象,以确保评级始终在0到5之间。这提供了单个收集成员的其他验证,而无需循环每个注入的对象。>
  • >严格键入的阵列和集合具有多个优点。它们在一个地方提供了简单的类型验证,确保在构造时始终对值进行验证,允许每个集合添加自定义逻辑,并减少在方法签名中混合参数的几率。
  • >可以添加方法以促进初始构造后的收集和价值对象的值进行编辑,但是在需要进行更改时,将它们保持不变并将其转换为原始类型是更有效的。进行更改后,可以使用更新的值重建集合或值对象,然后将再次验证。
  • >
  • 这篇文章首先出现在媒介上,并在作者的许可下重新发布。我们鼓励您在Medium上关注Bert,并在那里给他一些喜欢!
>在PHP 5.6中宣布的语言功能之一是添加...代币来表示函数或方法接受可变的参数。

我很少提到的东西是,可以将此功能与类型提示结合起来,从而基本上创建了键入的数组。> 例如,我们可以拥有一个电影类,其中一个方法可以设置一个仅接受dateTimeImmutable对象的空气日期。


我们现在可以将可变数量的单独的dateTimeImmutable对象传递给setairdates()方法:>

如果我们要通过dateTimeImmutable以外的其他内容,例如,将丢弃致命错误:

>

<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>
>如果我们已经有一系列DateTimeImmutable对象,我们想将其传递给SetairDates(),我们可以再次使用...

>数组包含一个不是预期类型的​​值,我们仍然会遇到前面提到的致命错误。

>此外,我们可以从php 7开始使用标量类型。

再次,这可以确保评级属性将始终包含浮子,而无需我们在所有内容上循环以验证它们。因此,现在我们可以在getaveragerating()中轻松地对它们进行一些数学操作,而不必担心无效的类型。
<span><span><?php
</span></span><span>
</span><span><span>class Movie {  
</span></span><span>  <span>private $dates = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
</span></span><span>    <span>$this->dates = $dates;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAirDates() {
</span></span><span>    <span>return $this->dates;
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>
> 这种打字数组的问题

>使用此功能作为键入数组的缺点之一是,我们只能定义每个方法的一个这样的数组。假设我们希望有一个电影类,该班级期望空气日期列表以及构造函数中的评分列表,而不是以后通过可选方法设置它们。上面使用的方法是不可能的。

>

>另一个问题是,当使用PHP 7时,我们的get()方法的返回类型仍然必须是“数组”,这通常太通用了。

>

解决方案:集合类

要解决这两个问题,我们可以简单地将我们的键入数组注入所谓的“收集”类中。这也改善了我们的关注点,因为我们现在可以将平均评级的计算方法移至相关集合类别:>

>请注意,我们仍在使用构造函数中具有可变长度的键入参数列表,这为我们节省了在每个评分上循环以检查其类型的麻烦。>

如果我们希望能够在foreach循环中使用此集合类,我们只需要实现iteratorAggregate界面:>

<span><span><?php
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span>
</span><span><span>$movie->setAirDates(
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22')
</span></span><span><span>);
</span></span>
>继续前进,我们还可以为我们的空气日期列表创建一个集合:>

在电影类中将所有难题的所有部分都放在一起,我们现在可以在构造函数中注入两个单独键入的集合。此外,我们可以在GET方法上定义比“数组”更具体的返回类型:>

使用自定义验证的值对象

<span><span><?php
</span></span><span>
</span><span><span>$dates = [
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-01-28'),
</span></span><span>  <span><span>\DateTimeImmutable</span>::createFromFormat('Y-m-d', '2017-02-22'),
</span></span><span><span>];
</span></span><span>
</span><span><span>$movie = new Movie();
</span></span><span><span>$movie->setAirDates(...$dates);
</span></span>
>如果我们想在评分中添加额外的验证,我们仍然可以进一步走一步,并使用一些自定义约束定义评级值对象。例如,额定值可能受到0至5之间的限制:

>回到我们的评分收集类中,我们只需要进行一些较小的更改即
<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Movie {
</span></span><span>  <span>private $dates = [];
</span></span><span>  <span>private $ratings = [];
</span></span><span>
</span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) { /* ... */ }
</span></span><span>  <span>public function getAirDates() : array { /* ... */ }
</span></span><span>
</span><span>  <span>public function setRatings(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverageRating() : float {
</span></span><span>    <span>if (empty($this->ratings)) {
</span></span><span>      <span>return 0;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>$total = 0;
</span></span><span>
</span><span>    <span>foreach ($this->ratings as $rating) {
</span></span><span>      <span>$total += $rating;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>return $total / count($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>

这样,我们将获得对单个收集成员的其他验证,但仍然不必循环每个注入的对象。

<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Ratings {
</span></span><span>  <span>private $ratings;
</span></span><span>
</span><span>  <span>public function __construct(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverage() : float {
</span></span><span>    <span>if (empty($this->ratings)) {
</span></span><span>      <span>return 0;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>$total = 0;
</span></span><span>
</span><span>    <span>foreach ($this->ratings as $rating) {
</span></span><span>      <span>$total += $rating;
</span></span><span>    <span>}
</span></span><span>
</span><span>    <span>return $total / count($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>
优点

键入这些单独的收集类和值对象似乎很重要,但是它们比通用数组和标量值具有多个优点:

>

<span><span><?php
</span></span><span>
</span><span><span>declare(strict_types=1);
</span></span><span>
</span><span><span>class Ratings implements IteratorAggregate {
</span></span><span>  <span>private $ratings;
</span></span><span>
</span><span>  <span>public function __construct(float ...$ratings) {
</span></span><span>    <span>$this->ratings = $ratings;
</span></span><span>  <span>}
</span></span><span>
</span><span>  <span>public function getAverage() : float { /* ... */ }
</span></span><span>
</span><span>  <span>public function getIterator() {
</span></span><span>     <span>return new ArrayIterator($this->ratings);
</span></span><span>  <span>}
</span></span><span><span>}
</span></span>
>

在一个地方轻松类型验证。我们永远不必手动循环浏览一个数组来验证我们的收集成员的类型; > 在应用程序中,无论我们在何处使用这些集合和价值对象,我们都知道它们的价值在构造时始终得到验证。例如,任何评分始终在0和5之间;

  • >

  • 我们可以轻松地添加每个集合和/或值对象的自定义逻辑。例如,我们可以在整个应用程序中重新使用getaverage()方法
  • >

    >
  • 我们有可能在单个函数或方法中注入多个键入列表,我们不能使用... doken来做,而无需先注入集合类中的值;
  • > 在方法签名中混合参数的几率大大减少。例如,当我们要注入评级列表和空气日期列表时,两者在使用通用阵列时很容易被偶然地混在一起;
  • 编辑呢?

    到目前

    >我们可以添加方法来促进编辑,但这很快就会变得麻烦,因为我们必须在每个集合上复制大多数方法,以保持类型提示的优势。例如,评分上的add()方法仅应接受评级对象,而airdates上的add()方法只能接受dateTimeMutable对象。这使得这些方法的接口和/或重复使用非常困难。
  • > 相反,我们可以简单地保留我们的收集和重视对象不可变的,并在需要进行更改时将它们转换为原始类型。完成更改后,我们可以简单地重建具有更新值的任何必要的集合或值对象。在(重新)构造后,所有类型都将再次验证,以及我们可能定义的任何额外验证。 例如,我们可以在收藏中添加一个简单的toarray()方法,然后进行这样的更改:>

    这样,我们也可以重新使用现有数组功能,例如array_filter()。

    >如果我们确实需要对收集对象进行编辑,则可以在需要的任何地方添加必要的方法。但是请记住,其中大多数也必须对给定参数进行类型验证,因此很难在所有不同的集合类中重新使用它们。

    重复使用通用方法

    >您可能已经注意到,通过在所有这些中实现ToArray()和GetIterator(),我们仍在在我们的集合课程中获得一些代码重复。幸运的是,这些方法足够通用,可以移至通用父类,因为它们都简单地返回注入的数组:>

    >我们将在收集类中留下的一切将是构造函数中的类型验证,以及任何特定于该集合的可选额外逻辑,例如:>
    <span><span><?php
    </span></span><span>
    </span><span><span>class Movie {  
    </span></span><span>  <span>private $dates = [];
    </span></span><span>
    </span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
    </span></span><span>    <span>$this->dates = $dates;
    </span></span><span>  <span>}
    </span></span><span>
    </span><span>  <span>public function getAirDates() {
    </span></span><span>    <span>return $this->dates;
    </span></span><span>  <span>}
    </span></span><span><span>}
    </span></span>
    >
    <span><span><?php
    </span></span><span>
    </span><span><span>class Movie {  
    </span></span><span>  <span>private $dates = [];
    </span></span><span>
    </span><span>  <span>public function setAirDates(\DateTimeImmutable ...$dates) {
    </span></span><span>    <span>$this->dates = $dates;
    </span></span><span>  <span>}
    </span></span><span>
    </span><span>  <span>public function getAirDates() {
    </span></span><span>    <span>return $this->dates;
    </span></span><span>  <span>}
    </span></span><span><span>}
    </span></span>

    >可选的是,我们可以使我们的集合最终取得最终成绩,以防止任何儿童类都以可以消除我们的类型验证的方式弄乱了属性。>

    结论

    >虽然远非完美,但它稳步地使用php的最新发行版中的集合和价值对象中的类型验证变得越来越容易。

    >理想情况下,我们将在未来版本的PHP中获得某种形式的仿制药,以进一步促进可重复使用的收集类的创建。

    >

    >大大改善价值对象使用的功能将是除字符串之外,还可以将对象施放给不同的原始类型。可以通过添加与__tostring()相当的额外魔法方法来轻松实现,例如__toint(),__tofloat()等。

    >幸运的是,正在进行一些RFC,可以在以后的版本中实现这两个功能,因此手指交叉了! ?

      generics:https://wiki.php.net/rfc/generics
    • 通用数组:https://wiki.php.net/rfc/generic-arrays
    • >

    • 将对象铸成标量:https://wiki.php.net/rfc/class_casting_to_to_scalar
    • >

    >如果您发现本教程有帮助,请访问Medium上的原始帖子,并给它一些❤️。如果您有任何反馈,疑问或评论,请在下面或原始帖子上留下回答。
    经常询问的问题(常见问题解答)有关在PHP

    >中创建严格键入的数组和收藏

    >在PHP中使用严格键入数组的好处是什么好处?这在数据一致性至关重要的较大,更复杂的应用中特别有用。通过为数组中的所有元素执行特定类型,您可以防止由于意外数据类型而可能发生的潜在错误和错误。这也使您的代码更容易预测,更易于调试,因为您始终知道您正在使用的数据类型。

    如何在PHP中创建一个严格键入的数组?不本地支持严格键入的数组。但是,您可以创建一个类,该类可以对添加到数组中添加的元素进行检查。此类将具有添加和检索元素的方法,这些方法将在执行操作之前检查元素的类型。如果该元素的类型与预期类型不匹配,则会丢弃错误。

    我可以使用php?

    中的数组使用类型提示,是的,PHP支持对数组的类型提示。您可以通过在函数或方法声明中的参数名称之前添加“数组”来指定函数或方法将数组作为参数的期望。但是,这仅确保参数是数组,而不是数组中的所有元素均为特定类型。

    >松散键入和严格键入的数组之间有什么区别?在严格键入的数组中,所有元素必须是特定类型的。如果您尝试在严格键入的数组中添加其他类型的元素,则将丢弃错误。

    >

    >如何执行PHP?

    >

    >您可以强制执行检查中的检查PHP通过使用“声明(strict_types = 1);”;指令在您的PHP文件开始时。这将强制执行严格的类型检查文件中的所有函数调用和返回语句。

    我可以在PHP中创建一个严格键入的对象数组? PHP中的对象通过创建一个类型的类,该类可以在添加到数组中添加的对象上检查。该类将具有添加和检索对象的方法,并且这些方法在执行操作之前会检查对象的类型。

    php?

    的严格键入数组的局限性是什么? PHP中严格键入数组的主要限制是它们需要其他代码才能实现,因为PHP并未在本地支持它们。这可以使您的代码更加复杂和难以维护。此外,严格键入的数组可以比松散键入的数组更灵活,因为它们不允许使用不同类型的元素。

    我可以使用php?

    的多维数组的类型提示,是的,是的。您可以使用PHP中的多维阵列使用类型提示。但是,PHP的类型暗示仅确保参数是一个数组,而不是数组(或子阵列)中的所有元素均为特定类型。 php?

    在PHP中使用严格键入数组时,您可以使用try-catch块来处理错误。如果将元素添加到数组时发生错误(例如,如果元素是错误的类型),则将抛出异常。您可以捕获此例外并适当处理。

    我可以使用具有PHP的内置数组函数的严格键入数组吗?

    是的,您可以使用PHP的内置阵列使用严格键入的数组功能。但是,您需要小心,因为这些功能不会强制执行检查。如果您使用修改数组的函数并添加错误类型的元素,则可能会导致错误。

    >

    以上是在PHP中创建严格键入的数组和收集的详细内容。更多信息请关注PHP中文网其他相关文章!

    声明:
    本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn