gugglegum/abstract-entity

实体(模型)的抽象类

1.1.3 2020-01-24 23:00 UTC

This package is auto-updated.

Last update: 2024-09-10 06:12:51 UTC


README

此类用作具有实体(模型)的类的基类。从该基类扩展的实体将获得通过getter和setter操作属性的函数。构造方法允许传递一个数组,该数组将被用于初始化新对象。它还包含getGetter()getSetter()方法,用于将属性名称转换为getter和setter方法。对于每个实体类属性(应该是私有的),你需要生成一对getter和setter。你可以在你的IDE中(我使用PhpStorm)使用这些方法的自动生成。

抽象实体从其属性中获取具体实体的属性列表(使用ReflectionClass)。你可以重新定义此方法以添加一些额外的处理。你可以添加一些虚拟属性,这些属性不是作为类属性存在的,或者删除一些不应作为属性使用的特殊属性。

版本1.1.0的发行说明

这个小版本更新包含了许多惊人的改进。最重要的是,我在之前的版本中找到了一个与类方法getAttributeNames()hasAttribute()中的静态变量相关的错误。它们被用来缓存实体属性列表,这些属性最初是通过\ReflectionClass从所有父类检索的。这是一个潜在的低速操作,这就是为什么我在类级别上缓存了它们。但是,这些静态变量可能导致意外的行为,如果父类中的静态变量在子类加载之前被初始化,即这个错误的再现与你的类加载和使用的顺序有关。通常,你无法控制这个顺序,因为使用了类自动加载器。这就是为什么调试这个错误很困难。

我对它有所怀疑,我开始编写单元测试来覆盖所有代码。第一次所有的测试看起来都很好,所以我稍微放松了一下。但是,然后它在非常意外的地方崩溃了。这是由于单元测试执行的特殊顺序的结果。PHPUnit在一个系统进程中执行所有测试,所以第一个测试可能影响最新的测试。我调查了这个,并编写了特殊的测试来重现这个错误。

然后我使用这些测试来确保错误完全修复。我决定完全拒绝类方法中的静态变量,因为它们非常不可预测,在某些情况下无法控制。现在我使用具有二维数组的类静态属性,其中第一级是具体模型类的名称。

还有一些其他改进

  • 为所有由AbstractEntity生成的异常设置用户定义的异常类。当你在做一些组件时,这可能非常有用,你不想泄露第三方组件内部实现的细节。你的组件通常有自己的异常类,这就是用户使用你的组件需要知道的一切。用户不应该记住你用来从你的组件中捕获所有异常的AbstractEntity。
  • getAttributeNames()方法现在只返回非静态属性,即如果你的模型类或其父类有静态属性,则它将不包括在列表中。
  • hasAttribute()现在是一个静态方法。作为静态方法,你仍然可以通过非静态调用调用它。所以这不会破坏向后兼容性。
  • 添加了PHPUnit测试,删除了旧测试目录。
  • 添加了使用示例。

要求

这个类是为了在PHP 7.0或更高版本上执行而编写的。它在方法定义中使用define(strict_types=1)和标量类型。

示例

实体类示例

<?php

declare(strict_types=1);

use gugglegum\AbstractEntity\AbstractEntity;

class User extends AbstractEntity
{
    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $email;

    /**
     * @var bool
     */
    private $isAdmin = false;

    /**
     * @var bool
     */
    private $disabled = false;

    /**
     * @return string|null
     */
    public function getName(): ?string
    {
        return $this->name;
    }

    /**
     * @param string|null $name
     * @return self
     */
    public function setName(?string $name): self
    {
        $this->name = $name;
        return $this;
    }

    /**
     * @return string|null
     */
    public function getEmail(): ?string
    {
        return $this->email;
    }

    /**
     * @param string|null $email
     * @return self
     */
    public function setEmail(?string $email): self
    {
        $this->email = $email;
        return $this;
    }

    /**
     * @return bool
     */
    public function isAdmin(): bool
    {
        return $this->isAdmin;
    }

    /**
     * @param bool $isAdmin
     * @return User
     */
    public function setIsAdmin(bool $isAdmin): self
    {
        $this->isAdmin = $isAdmin;
        return $this;
    }

    /**
     * @return bool
     */
    public function isDisabled(): bool
    {
        return $this->disabled;
    }

    /**
     * @param bool $disabled
     * @return self
     */
    public function setDisabled(bool $disabled): self
    {
        $this->disabled = $disabled;
        return $this;
    }
}

测试用法

<?php

require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/User.php';

$user = User::fromArray([
    'name' => 'John',
    'email' => 'john@example.com',
    'isAdmin' => false,
    'disabled' => true,
]);

var_dump($user->toArray());

如果您想在模型中使用自己的异常类,最佳解决方案是在模型的构造函数中定义它。但请注意,您应该在调用parent::__construct($data)之前设置异常类,因为父构造函数可能会抛出异常。