aedart / overload
通过实现 PHP 的魔术方法(__get(), __set(), __isset(), 和 __unset())提供动态处理不可访问属性的方法;此包强制使用 getter 和 setter 方法,确保如果属性确实存在,则其对应的 getter
Requires
- php: >=7.1.0
- illuminate/support: 5.6.*
Requires (Dev)
- aedart/license: 1.*
- aedart/license-file-manager: ~2.0
- aedart/testing: ~2.0
README
已废弃 - Overload
包已被 aedart/athenaeum 替换
提供动态处理不可访问属性的方法,通过实现 PHP 的魔术方法;__get(),__set(),__isset() 和 __unset()。然而,此包强制使用 getter 和 setter 方法,确保如果属性确实存在,则其对应的 getter 或 setter 方法将被调用。在此上下文中,“重载”一词指的正是 PHP 的自身定义。(https://php.ac.cn/manual/en/language.oop5.overloading.php)
内容
何时使用此包
通常情况下,魔术方法的使用可能非常麻烦。大部分情况下,它们会禁止 IDE 中的自动完成功能,如果没有文档,开发人员被迫阅读大量源代码,才能理解正在发生的事情。根据实现方式,在动态给对象分配新属性时可能没有任何验证,这可能会破坏依赖于该对象的组件。此外,对使用此类魔术方法的组件编写测试也可能非常困难。
此包不能解决上述任何问题,因为最终,作为开发人员,您仍然必须确保代码可读、可理解、可测试和有文档。因此,我建议只有在以下所有条件都满足的情况下,才使用此包;
- 不应允许在不了解它们的情况下动态创建和将属性分配给对象。因此,属性必须始终预先定义。
- 必须始终使用 getter 和 setter 来读取和写入属性
- 您希望允许以这种方式访问对象的属性:$person->age;并仍能进行某种验证。
如何安装
composer require aedart/overload
此包使用 composer。如果您不知道它是做什么的或它是如何工作的,我建议在尝试使用此包之前先了解一下。
快速入门
典型类
<?php use Aedart\Overload\Traits\PropertyOverloadTrait; /** * @property string $name Name of a person */ class Person { use PropertyOverloadTrait; /** * Name of a person * * @var string|null */ protected $name = null; // This is made accessible, because of the PropertyOverloadTrait. // When attempted to read, getName() is invoked // When attempted to write, setName($value) is invoked // A getter method for $name public function getName() : string { return $this->name; } // A setter method $name public function setName(string $value) { if( ! empty($value)){ $this->name = $value; return; } throw new InvalidArgumentException('Provided name is invalid'); } } // Some place else, in your application, you can then invoke the following: $person = new Person(); $person->name = 'Alin'; // Invokes the setName(...) echo $person->name; // Invokes the getName(), then outputs 'Alin' echo isset($person->name); // Invokes the __isset(), then outputs true unset($person->name); // Invokes the __unset() and destroys the name property
提示:PHPDoc
当使用PHP的魔术方法进行属性重载时,利用PHPDoc的@property
标签是一个非常好的主意。大多数IDE都可以读取它,并利用它提供自动完成功能。请参阅http://www.phpdoc.org/docs/latest/references/phpdoc/tags/property.html
命名规范应用
属性名称
此包假设您的属性遵循驼峰命名法或蛇形命名法标准。请考虑以下示例
<?php $personId = 78; // Valid $category_name = 'Products'; // Valid $swordFish_length = 63; // Invalid, because its a mix of both camelCase and underscore
获取器/设置器名称
获取器和设置器遵循最严格的命名规范;它们必须遵循驼峰命名法,并以get
为前缀作为获取器方法,以set
为前缀作为设置器方法。此外,在搜索属性对应的获取器或设置器时,包使用以下语法/规则
getterMethod = getPrefix, camelCasePropertyName;
getPrefix = "get";
setterMethod = setPrefix, camelCasePropertyName;
setPrefix = "set";
camelCasePropertyName = {uppercaseLetter, {lowercaseLetter}};
uppercaseLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K"
| "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X"
| "Y" | "Z" ;
lowercaseLetter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k"
| "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z" ;
上述语法/规则用EBFN表示
示例
<?php $personId = 78; // Will look for getPersonId() and setPersonId($value); $category_name = 'Products'; // Will look for getCategoryName() and setCategoryName($value);
受保护属性与私有属性
默认情况下,只有protected
属性会被设置为可访问的(或者,如果你愿意,重载)。这意味着声明为private
的属性将不可用。
<?php use Aedart\Overload\Traits\PropertyOverloadTrait; class Person { use PropertyOverloadTrait; protected $name = null; // This is made accessible, because of the PropertyOverloadTrait. // When attempted to read, getName() is invoked // When attempted to write, setName($value) is invoked private $age = null; // Is NOT made accessible, read / write attempts will result in Exception // Remaining implementation not shown... }
行为覆盖
如果您希望公开声明的私有属性,则可以通过对象内部的作用域来设置此行为。
<?php use Aedart\Overload\Interfaces\PropertyAccessibilityLevel; use Aedart\Overload\Traits\PropertyOverloadTrait; class Person { use PropertyOverloadTrait; protected $name = null; // This is made accessible, because of the PropertyOverloadTrait. // When attempted to read, getName() is invoked // When attempted to write, setName($value) is invoked private $age = null; // This is made accessible, because of the $this->setPropertyAccessibilityLevel(...). // When attempted to read, getName() is invoked // When attempted to write, setName($value) is invoked public function __construct(){ // Change the property accessibility to private $this->setPropertyAccessibilityLevel(PropertyAccessibilityLevel::PRIVATE_LEVEL); } }
有关进一步参考,请阅读Overload/Traits/Helper/PropertyAccessibilityTrait
中的文档
自定义使用
如果您不需要完整的属性重载方法,例如,您只希望能够获取和设置,但不希望取消设置属性,则可以使用由PropertyOverloadTrait
组成的子特性。
但是,在使用单独的特性时,您还必须包括Aedart\Overload\Traits\Helper\ReflectionTrait
,否则特性将无法按预期工作;将抛出一个致命错误,表明无法找到各种方法!
以下列出的每个特性都可以独立使用,而不依赖于彼此。
特性 | 描述 | 命名空间 |
---|---|---|
ReflectionTrait | 必须始终包含 | Aedart\Overload\Traits\Helper\ReflectionTrait |
GetterInvokerTrait | 实现__get() |
Aedart\Overload\Traits\GetterInvokerTrait |
SetterInvokerTrait | 实现__set() |
Aedart\Overload\Traits\SetterInvokerTrait |
IssetInvokerTrait | 实现__isset() |
Aedart\Overload\Traits\IssetInvokerTrait |
UnsetInvokerTrait | 实现__unset() |
Aedart\Overload\Traits\UnsetInvokerTrait |
贡献
您是否发现了缺陷(错误或设计缺陷),或者您希望改进?在以下部分,您可能会找到有关如何帮助此项目的有用信息。无论如何,我都感谢您抽出时间帮助我改进此项目的交付成果和整体质量。
错误报告
如果您确信找到了一个错误,那么至少您应该创建一个新的问题。在该问题中,您至少应该描述以下内容;
- 缺陷位于何处
- 对缺陷的良好、简短且精确的描述(为什么是缺陷)
- 如何复现缺陷
- (解决缺陷的可能方法)
有时间的话,我会审查您的问题并采取行动。
分支代码并发送pull-request
一份良好且书写规范的错误报告可以极大地帮助我。尽管如此,如果您可以或愿意自行解决缺陷,以下是您可以这样做的方式;
- 分支此项目
- 为特定缺陷修复创建一个新的本地开发分支
- 编写代码/更改
- 创建可执行的测试用例(证明您的更改是稳固的!)
- 提交并将更改推送到您的分支仓库
- 发送包含您的更改的pull-request
- 喝一杯啤酒 - 您应得的 :)
一旦我收到pull-request(并有时间处理),我会审查您的更改并将它们合并到项目中。如果没有,我会通知您为什么我选择不合并。
版本控制
此软件包遵循语义版本控制2.0.0
许可证
BSD-3-Clause,阅读本包中包含的LICENSE文件