arc / prototype
ARC:原型继承组件
Requires
- php: >=7.1
Requires (Dev)
- phpunit/phpunit: 9.*
README
arc/prototype
此组件向PHP添加原型,包括所有JavaScript特性,如Object.extend、Object.assign、Object.freeze和Object.observe。它还支持每个属性的设置器和获取器。
创建原型对象
$object = \arc\prototype::create();
添加属性
$object->foo = 'Foo';
添加方法
$object->bar = function() { return $this->foo.'bar'; }
扩展对象
$childObject = \arc\prototype::extend($object); $childObject->foo = 'Vue'; echo $childObject->bar();
快速创建
$object = \arc\prototype::create([ 'foo' => 'Foo', 'bar' => function() { return $this->foo.'bar'; } ]);
快速扩展
$childObject = \arc\prototype::extend($object, [ 'foo' => 'Vue' ]);
设置器和获取器
$object->guarded = [ 'set' => function($value) { if ( $value !== 'Foo' ) { $this->unguarded = $value; } }, 'get' => function() { return 'Foo'.$this->unguarded; } ];
如果你只有'set'函数,获取值将始终返回'null'。如果你只有'get'函数,设置值将不起作用。
对象最终化
\arc\prototype::preventExtension($object); $childObject = \arc\prototype::extend($object);
这将抛出\BadMethodCallException。
$isExtensible = \arc\prototype::isExtensible($object); // returns false
对象密封
$object->foo = 'Foo'; \arc\prototype::seal($object); $object->foo = 'Bar';
这将抛出\LogicException。
$isExtensible = \arc\prototype::isExtensible($object); // returns false
$isSealed = \arc\prototype::isSealed($object); // returns true
## Freezing objects
```php
$object->foo = 'Foo';
\arc\prototype::freeze($object);
$object->foo = 'Bar';
这将抛出\LogicException。
$isExtensible = \arc\prototype::isExtensible($object); // returns false
$isSealed = \arc\prototype::isSealed($object); // returns true
$isFrozen = \arc\prototype::isFrozen($object); // returns true
观察变化
$log = []; \arc\prototype::observe($object, function($changes) use (&$log) { $log[] = $changes; });
或限制观察器仅针对特定类型的更改
$log = []; \arc\prototype::observe($object, function($changes) use (&$log) { $log[] = $changes; }, ['add','delete']);
如果没有设置,将观察所有更改类型:'add'、'update'、'delete'、'reconfigure'。
设置器、获取器和超级私有
function makeAFoo() { $superPrivate = 'Shhh...'; $object = \arc\prototype::create(); $object->foo = [ 'get' => function() use (&$superPrivate) { return $superPrivate; } ]; $object->doFoo = function($value) use (&$superPrivate) { $superPrivate = 'Shhh... '.$value; }; return $object; }
通过使用不是原型对象属性的变量,但在多个对象方法的作用域内,你可以创建类似于私有属性的东西。但它比普通的私有属性更私密,甚至此对象中的其他方法也无法访问这个变量。这被称为javascript中的'SuperPrivate'。
将arc\prototype用作依赖注入容器
<?php $di = \arc\prototype::create([ 'dsn' => 'mysql:dbname=testdb;host=127.0.0.1'; 'user' => 'dbuser', 'password' => 'dbpassword', 'database' => \arc\prototype::memoize( function() { // this generates a single PDO object once and then returns it for each subsequent call return new PDO( $this->dsn, $this->user, $this->password ); } ), 'session' => function() { // this returns a new mySession object for each call return new mySession(); } ] ); $diCookieSession = \arc\prototype::extend( $di, [ 'session' => function() { return new myCookieSession(); } ] );
注意:PHP有一个限制,就是你永远不能将静态函数绑定到对象上。这将导致不可捕获的致命错误。为了解决这个问题,你必须通过在名称前加":"来告诉原型该闭包是静态的。在这种情况下,该方法的第一个参数将始终是当前对象。
<?php class foo { public static function myFactory() { return \arc\prototype::create([ 'foo' => 'Foo', ':bar' => function($self) { return $self->foo; }, 'baz' => [ ':get' => function($self) { return 'Baz'; } ] ]); } } $f = foo::myFactory(); echo $f->bar(); // outputs: "Foo";
静态闭包是在静态函数中定义的所有闭包,或者明确定义为静态的。在类作用域外定义的闭包可以被绑定,不需要这个解决方案。
方法
\arc\prototype::create
(object) \arc\prototype::create( (array) $properties )
返回一个具有给定属性的新\arc\prototype\Prototype对象。属性数组可能包含闭包,这些闭包将作为新Prototype对象上的方法可用。
\arc\prototype::extend
(object) \arc\prototype::extend( (object) $prototype, (array) $properties )
这返回一个具有给定属性的新Prototype对象,就像\arc\prototype::create()一样。但除此之外,新对象还有一个原型属性,将其链接到原始对象,该对象从中扩展而来。原始对象上的任何方法或属性也将通过其原型链在新对象中可用。
你可以通过获取\arc\prototype\Prototype对象的原型属性来检查对象的原型。你不能更改此属性 - 它是只读的。你只能通过使用扩展方法来设置原型属性。
\arc\prototype::assign
(object) \arc\prototype::extend( (object) $prototype, (object) ...$objects )
这返回一个具有给定原型的新的Prototype对象。此外,传递给此方法的额外对象上的所有属性都将复制到新的Prototype对象。对于在多个对象上设置的任何属性,较晚对象上的属性值将覆盖来自其他对象的值。
\arc\prototype::freeze
(void) \arc\prototype::freeze( (object) $prototype )
这将使对给定Prototype对象的更改变得不可能。对象变为不可变的。任何尝试更改对象的操作都将静默失败。对象也被密封,不再可扩展。唯一解冻它的方法是通过克隆对象。克隆将被解冻、解密并可用于扩展。
\arc\prototype::isFrozen
(bool) \arc\prototype::isFrozen( (object) $prototype )
如果此对象被冻结且不可变,则返回true。
\arc\prototype::seal
(void) \arc\prototype::seal( (object) $prototype )
这使对象无法添加或删除属性,也无法重新配置它们。对象也不再开放扩展。唯一解封它的方法是克隆它。克隆将不受限制并开放扩展。
\arc\prototype::isSealed
(bool) \arc\prototype::isSealed( (object) $prototype )
如果此对象已密封且属性无法重新配置、添加或删除,则返回true。
\arc\prototype::preventExtensions
(void) \arc\prototype::preventExtensions( (object) $prototype )
这使对象无法添加属性或扩展它。
\arc\prototype::isExtensible
(bool) \arc\prototype::isExtensible( (object) $prototype )
如果此对象开放扩展,则返回true。
\arc\prototype::observe
(void) \arc\prototype::observe( (object) $prototype, (Closure) $f )
每次$prototype的属性发生变化时,都会调用闭包$f。闭包使用原型对象、属性名称和新值调用。如果闭包返回精确的false(其他'falsy'值将不起作用),则更改将被取消。
<?php \arc\prototype::observe($object, function($object, $name, $value) { if ( $name === 'youcanttouchthis' ) { return false; } });
\arc\prototype::unobserve
(void) \arc\prototype::unobserve( (object) $prototype, (Closure) $f )
从Prototype对象中删除特定的观察器函数。您必须传递完全相同的闭包才能使其工作。
\arc\prototype::getObservers
\arc\prototype::hasProperty
(bool) \arc\prototype::hasProperty( (string) $propertyName )
如果请求的属性当前原型对象本身或其任何原型中可用,则返回true。
\arc\prototype::keys
(array) \arc\prototype::keys( (object) $prototype )
\arc\prototype::values
(array) \arc\prototype::values( (object) $prototype )
\arc\prototype::entries
(array) \arc\prototype::entries( (object) $prototype )
\arc\prototype::ownKeys
(array) \arc\prototype::ownKeys( (object) $prototype )
\arc\prototype::ownValues
(array) \arc\prototype::ownValues( (object) $prototype )
\arc\prototype::ownEntries
(array) \arc\prototype::ownEntries( (object) $prototype )
\arc\prototype::hasOwnProperty
(bool) \arc\prototype::hasOwnProperty( (string) $propertyName )
如果请求的属性当前原型对象本身即可用,而无需检查其原型链,则返回true。
\arc\prototype::hasPrototype
(bool) \arc\prototype::hasPrototype( (string) $prototypeObject )
如果给定对象是当前原型对象原型链的一部分,则返回true。
\arc\prototype::getDescendants
(array) \arc\prototype::getDescendants( (object) $prototype )
\arc\prototype::getInstances
(array) \arc\prototype::getInstances( (object) $prototype )
\arc\prototype::getPrototypes
(array) \arc\prototype::getPrototypes( (object) $prototype )
\arc\prototype::memoize
(Closure) \arc\prototype::memoize( (callable) $f )
返回一个函数,该函数只会运行一次。在第一次运行后,它将返回运行返回的值,除非该值为null。这使得可以创建仅在需要时运行的延迟加载函数。您还可以在依赖注入容器中创建共享对象。
此方法不保证给定的函数永远不会运行多次 - 除非您始终通过产生的闭包间接调用它。