bapcat / propifier
改进PHP属性的特质
3.1
2023-10-12 17:47 UTC
Requires
- php: ^8.1
- icanboogie/inflector: ^2.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- roave/security-advisories: dev-master
README
Propifier
一个为PHP添加真正面向对象属性支持的特质。
安装
Composer
Composer 是安装所有BapCat包的推荐方法。
$ composer require bapcat/propifier
GitHub
可以从 GitHub 下载BapCat包。
PHP "属性"的问题
从像.NET这样的其他语言过来的任何人可能会习惯于定义属性(访问器和修改器)来控制对类私有变量的访问。不幸的是,PHP缺少对这项有用特性的支持。有几种解决方案...
公共属性
class Foo { public $a; public $b; }
使用公共属性是最简单的,但完全缺乏封装性。您无法控制谁可以更改对象的内部状态。
__get
和 __set
class Foo { private $a; private $b; public function __get($name) { if(isset($this->$name)) { return $this->$name; } throw new Exception('Invalid property!'); } public function __set($name, $value) { switch($name) { case 'a': $this->a = $value; break; case 'b': throw new Exception('b is read-only!'); } throw new Exception('Invalid property!'); } }
使用PHP的后期绑定支持可以控制对对象可读和可写的内容,但牺牲了可读性、效率和类型提示。而且,不使用其他解决方案,这种方法也无法控制数组的读写访问。
... private $array = []; ... public function __get($name) { if(isset($this->$name)) { return $this->$name; } } public function __set($name, $value) { throw new Exception('You can\'t set me!'); } ... $foo = new FooWithArrayThatCantBeSet(); $foo->array['a'] = 'Test'; // Note: no exception echo $foo->array['a']; // -> 'Test'
获取器和设置器
class Foo { private $a; private $b; private $array = []; public function getA() { return $this->a; } public function setA(A $a) { $this->a = $a; } public function getB() { return $this->b; } public function getOnlyOneArrayValue($index) { return $this->array[$index]; } }
使用Java风格的获取器和设置器是PHP中实现属性的最佳方法之一,但仍然存在缺陷。它非常冗长
$a = $foo->getA(); // rather than $foo->a
您还必须放弃使用数组访问语法来访问数组属性
$one_array_value = $foo->getOnlyOneArrayValue(1); // rather than $foo->array[1]
Propifier方式
Propifier解决了这些问题中的每一个。
class Foo { use \BapCat\Propifier\PropifierTrait; private $a; private $b; private $array = []; public function __construct() { $a = null; $b = new B(); $array['test'] = 'Test'; } protected function getA() { return $this->a; } protected function setA(A $a) { // Type hinting $this->a = $a; } protected function getB() { return $this->b; } // Controlled access //protected function setB(B $b) { // $this->b = $b; //} // Propifier automatically detects arrays, and // allows array access when using the property protected function getArray($index) { return $this->array[$index]; } // You can even define iterators to add foreach support protected function itrArray() { return new ArrayIterator($this->array); } }
$foo = new Foo(); echo $foo->a; // -> null $foo->a = new A(); // $a == new instance of A echo $foo->b; // -> instance of B $foo->b = new B(); // exception echo $foo->array['test']; // -> 'Test' $foo->array = []; // exception $foo->array[1] = 'Test?'; // exception foreach($foo->array as $key => $value) { // ... }
效率
Propifier将使您在编写重要代码时更加高效,并且与类似解决方案不同,Propifier从一开始就被设计成快速。它一开始就计算出所有内容,并维护所有对象的属性静态映射,因此使用它们总是很快。