aedart/overload

此包已被废弃,不再维护。作者建议使用 aedart/athenaeum 包。

通过实现 PHP 的魔术方法(__get(), __set(), __isset(), 和 __unset())提供动态处理不可访问属性的方法;此包强制使用 getter 和 setter 方法,确保如果属性确实存在,则其对应的 getter

5.1.0 2018-09-15 07:04 UTC

README

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

已废弃 - 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文件