肉磨坊 / core
禁用PHP对象的默认行为。
Requires
- php: ^7.0
Requires (Dev)
- codeclimate/php-test-reporter: ^0.4
- phpunit/phpunit: ^6.0
- satooshi/php-coveralls: ^1.0
- scrutinizer/ocular: ^1.3
Suggests
- fleshgrinder/comparable: For a consistent and type safe comparison contract for objects.
- fleshgrinder/equalable: For a consistent equals contract for objects.
This package is not auto-updated.
Last update: 2020-01-24 17:09:28 UTC
README
核心
核心库提供了PHP核心(以及很可能会永远无法进入它)中最基本的功能:禁用默认PHP对象行为的助手(以特质的形式)。
安装
打开终端,进入您的项目目录并执行以下命令以将此软件包添加到依赖项
composer require fleshgrinder/core
此命令要求您全局安装Composer,如Composer文档中的安装章节中所述。
使用
解除魔法
解除魔法特质可用于禁用对魔法__get
、__isset
、__set
和__unset
方法的支持。PHP中的每个对象默认都支持这些方法以进行动态属性管理。然而,这些是在几乎所有情况下都不希望拥有的功能。虽然对这些方法的支持不会导致严重的错误,但它可能导致一些奇怪的行为。尤其是在值对象的情况下,当使用PHP的相等运算符(==
)确定相等性时。
假设我们有一个简单的值对象
final class ValueObject { private $value; public function __construct($value) { $this->value = $value; } }
使用相等运算符确定两个实例是否相等非常直接,比较也是如此
$v0 = new ValueObject(0); $v1 = new ValueObject(1); var_dump( $v0 < $v1, // true $v0 <= $v1, // true $v0 == $v1, // false $v0 >= $v1, // false $v0 > $v1 // false );
如果我们现在向$v0
添加一个属性,结果将不同
$v0 = new ValueObject(0); $v0->x = 42; $v1 = new ValueObject(1); var_dump( $v0 < $v1, // false $v0 <= $v1, // false $v0 == $v1, // false $v0 >= $v1, // true $v0 > $v1 // true );
当然,这些运算符不应该使用,而应该使用专门的功能,如Equalable和Comparable,但此特质几乎不需要任何成本就为整个程序增加了另一层安全性。
此特质非常有用的其他情况是如果您的对象依赖于它们拥有的属性。例如,如果使用get_object_vars
。但是请注意,并非所有可能奇怪的行为都通过包含此特质来解决。例如,仍然可以通过精心制作的unserialize
字符串动态添加属性。这是因为PHP在这种情况下不会调用任何这些魔法方法,而是直接将属性添加到对象中,请在您的__wakeup
或unserialize
方法中验证对象。
不可克隆
不可克隆特质可用于禁用在客户端代码中对clone
关键字的调用。对于无法克隆的技术原因的对象,例如包含某种资源(例如数据库连接)的对象,或者不应该克隆因为它没有意义(例如任何类型的不可变实现,如值对象)的对象,这是一个好主意。
在这个特质中,魔法方法__clone
被定义为final和protected,这确保了使用该特质的类的子类无法修改该契约。同时,它允许使用该特质的类内部使用克隆功能,以提供无中断的写时复制支持;如下例所示
final class URI { use Fleshgrinder\Core\Uncloneable; // ... public function withFragment(string $fragment): URI { $clone = clone $this; $clone->fragment = $fragment; return $clone; } }
另一个有趣的用例是与建造者模式配对的友元类,用于提供不可变实体。
abstract class EntityFriend { use Fleshgrinder\Core\Uncloneable; protected $value; protected function setValue(T $value): void { $this->value = $value; } } final class Entity extends EntityFriend { public function getValue(): T { return $this->value; } } final class EntityBuilder extends EntityFriend { private $entity; public function __construct() { $this->entity = new Entity; } public function build(): Entity { return clone $this->entity; } public function setValue(T $value): void { $this->entity->setValue($value); } }
不可构造
可以使用Unconstructable特质来禁用在客户端代码中对new
关键字的支持。几乎总是建议禁用多次构造函数调用并强制实际构造函数方法参数的不变性。当然,这个类需要命名构造函数,否则构造将是不可能的。
final class SomeClass { use Fleshgrinder\Core\Unconstructable; public static function new(): self { return new static; } }
另一个用例是PHP中没有的final abstract类。
final class AbstractFinalClass { use Fleshgrinder\Core\Unconstructable; public static function f() { } public static function f′() { } // ... }
不可变
Immutable是所有其他特质的组合,仅为了方便使用。它最好用于任何类型的不可变类,正如其名称所暗示的那样。
测试
打开终端,进入项目目录,并执行以下命令以运行您本地安装的PHP可执行文件与PHPUnit测试。
make
如果系统上没有make
,您还可以执行以下两个命令。
composer install
composer test