gugglegum / abstract-entity
实体(模型)的抽象类
Requires
- php: >=7.0.0
Requires (Dev)
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)
之前设置异常类,因为父构造函数可能会抛出异常。