clj/protocol

clojure 协议的 PHP 版本

1.0.0 2012-05-30 16:15 UTC

This package is not auto-updated.

Last update: 2024-09-28 12:15:54 UTC


README

#PHP 的 Clojure 协议

##什么是协议?

有关更多信息,请参阅 Details.md 文件

##创建协议

  1. 创建一个接口,包含你想要协议实现的函数。接口中每个函数的第一个参数必须是调用对象。因此,创建你的接口如下

     interface ILookup
     {
         public function get($context, $key, $default = null);
         public function exists($context, $key);
     }
    

    而不是这样

     interface ILookup
     {
         public function get($key, $default = null);
         public function exists($context, $key);
     }
    
  2. 创建实现接口的协议

     class Lookup extends \Clj\AProtocol
     {
         public function get($object, $key, $default = null)
         {
             return $this->__getObject__($object)->get($object, $key, $default);
         }
         public function exists($object, $key)
         {
             return $this->__getObject__($object)->exists($object, $key);
         }
     } 
    

    __getObject__ 方法找到对象的类型,并返回协议的具体实现

  3. 创建协议的具体实现(在我的代码中,我将实现类型名称的前缀设置为 P,例如 PNull 表示 null 或 PDateTime 表示 DateTime 对象)

     class PArray extends \Clj\AProtocolInstance implements ILookup //Lookup for arrays
     {
         public function get($context, $key, $default = null)
         {
             if (isset($context[$key]) || (array_key_exists($key, $context)))
             {
                 return $context[$key];
             }
             return $default;
         }
    
         public function exists($context, $key)
         {
             return (isset($context[$key]) || (array_key_exists($key, $context)));
         }
     }
    
     class PNull extends \Clj\AProtocolInstance implements ILookup //Lookup for null
     {
         public function get($context, $key, $default = null)
         {
             return $default;
         }
    
         public function exists($context, $key)
         {
             return false;
         }
     }
    

##使用协议管理器

使用 Protocol manager 类创建和扩展协议。要添加协议,请传递协议对象

$lookup = new Lookup();
$protocol_manager->add($lookup);

要向协议添加类型,可以使用 extendType 或 extendProtocol 方法

//Extends a type to an array of protocols
$protocol_manager->extendType(\Clj\IProtocol::PROTOCOL_NULL, array('ILookup' => new PNull()));
//Extends the protocol to an array of types
$protocol_manager->extendProtocol('ILookup', array(\Clj\IProtocol::PROTOCOL_NULL => new PNull(),
    \Clj\IProtocol::PROTOCOL_ARRAY => new PArray()));

要检索扩展的协议,可以使用 getProtocol 或 getProtocolReference。以下是如何使用它们的示例

$lookup = new Lookup();
$protocol_manager->add($lookup);

$protocol_manager->extendType(\Clj\IProtocol::PROTOCOL_NULL, array('ILookup' => new PNull()));
//Gets the lookup protocol that only works for null types
$extended_lookup = $protocol_manager->getProtocol('ILookup');
$lookup_reference = $protocol_manager->getProtocolReference('ILookup');

$protocol_manager->extendType(\Clj\IProtocol::PROTOCOL_ARRAY, array('ILookup' => new PArray()));

$extended_lookup->get(null, 'foo', 'bar'); //Returns 'bar'
$extended_lookup->get(array('foo' => 'bar'), 'foo', 'bar'); //Throws excpetion

$lookup_reference->getRef()->get(null, 'foo', 'bar'); //Returns 'bar'
$lookup_reference->getRef()->get(array('foo' => 'BAZ'), 'foo', 'bar'); //Returns 'BAZ'

在示例中,getProtocol 返回在调用时存在的查找协议(仅针对 null 类型进行了扩展)。在之后对协议进行的任何扩展(将查找协议扩展到数组)都不会添加到 $extended_lookup 中。

相比之下,getProtocolReference 返回一个类似于 $a =& $b 的协议引用。但这个引用是只读的,并且通过 getRef 方法访问。这允许访问协议的所有扩展,而不仅仅是创建引用时存在的扩展。