Framework DSW项目周记1
本周实现了一个基于PHP的动态泛型方案。现在PHP可以按照下面的例子来使用泛型了:
<?php require_once 'FrameworkDSW/System.php'; /** * @param <T, P> <--这里是推荐的phpDoc定义方式 */ class TChild extends TObject { /** * @param T $p */ public function Func($p) { try { TType::Type($p, $this->GenericArg('T')); } catch (EInvalidTypeCasting $e) { echo get_class($e) . ' ($p is <div style="border: 1px solid"> ' . var_export($p, true) . '</div>)<br/>'; } } /** * @param T $t * @param P $p */ public function FuncTwo($t, $p) { try { TType::Type($t, $this->GenericArg('T')); } catch (EInvalidTypeCasting $e) { echo get_class($e) . ' ($t is <div style="border: 1px solid"> ' . var_export($t, true) . '</div>)<br/>'; } try { TType::Type($p, $this->GenericArg('P')); } catch (EInvalidTypeCasting $e) { echo get_class($e) . ' ($p is <div style="border: 1px solid"> ' . var_export($p, true) . '</div>)<br/>'; } } } echo '<p>TEST 1</p>'; TChild::PrepareGeneric(array ('T' => 'integer')); //相当于TChild<T: integer> $obj = new TChild(); $obj->Func(0); $obj->Func(new TObject()); //此处出错!不是integer $obj->Func(true); //不出错,因为true是可以转换成1的,根据PHP的==号规则 $obj->Func('string'); //不出错,因为可以转换成0,根据PHP的==号规则 echo '<p>TEST 2</p>'; TChild::PrepareGeneric(array ('T' => 'integer', 'P' => 'TObject')); $obj = new TChild(); $obj->FuncTwo(0, new TObject()); $obj->FuncTwo(new TObject(), 0); //出错,TObject不是integer,0不是TObject class TComplex extends TObject { /** * * @param T $t */ public function Func($t) { TType::Type($t, $this->GenericArg('T')); } } echo '<p>TEST 3</p>'; TChild::PrepareGeneric(array ('T' => 'integer', 'P' => 'boolean')); $c = new TChild(); TComplex::PrepareGeneric(array ('T' => array ('TChild' => array ('T' => 'integer', 'P' => 'boolean')))); $obj = new TComplex(); $obj->Func($c); $obj->Func(true);//出错:true不是TChild<T: integer, P: boolean>
注意我们的框架中的泛型是动态泛型。所谓的动态泛型就是在新建对象或者调用静态方法时,可以动态的指定泛型参数,而定义类或者静态方法时不需要指定所需要的泛型参数定义(虽然这个不是好习惯对于我来说,但是保证了PHP的灵活性),也就是说,在Java中需要这样定义和使用:
class Sample<T, P> { public static <Q> void Foo(Q param) { /*...*/ } public static void main(String[] args) { Sample<String, Integer> s = new Sample<String, Integer>(); //类的泛型 Sample.<Integer>Foo(100); //泛型方法 } }
而现在在PHP里面可以这样使用:
/** * @param <T, P> */ class TSample extends TObject { /** * @param Q $param */ public static function Foo($param) { /*...*/ } } TSample::PrepareGeneric(array ('T' => 'string', 'P' => 'integer')); $s = new TSample(); TSample::PrepareGeneric(array ('X' => 'string', 'Y' => array( 'TSample' => array ('Z' => 'string')))); $s2 = new TSample(); //动态就在这里体现出来了,现在$s2拥有的泛型参数和$s是完全不同的。 //$s的是<T: string, P: integer> //$s2的是<X: string, Y: TSample<Z: string>> TSample::PrepareGeneric(array ('Q' => 'integer')); TSample::Foo(100); TSample::PrepareGeneric(array ('P' => 'string')); TSample::Foo(100); //这个是方法泛型的动态。
最后,附上相关的API:
void TObject::PrepareGeneric(array $Args) //为下次创建对象或调用静态方法准备泛型的参数,如果需要的话。 mixed TObject::GenericArgs() //返回当前对象所有泛型参数的值。 mixed TObject::GenericArg(string $ArgName) //返回当前对象特定泛型参数名称的泛型参数值。 mixed TObject::StaticGenericArgs() //返回当前类的泛型参数值,泛型静态方法用。 mixed TObject::StaticGenericArgs(string $ArgName) //返回当前类的某一泛型参数的值,泛型静态方法用。 boolean TObject::IsInstanceOf(mixed $Type) //判断当前对象是不是$Type描述的类型。 mixed TObject::ObjectType() //返回当前对象的类型信息。 void TType::Type(mixed &$Var, mixed $Type) //确保$Var是$Type类型的变量。 void TType::Obejct(object &$Var, mixed $Type) //确保$Var是$Type类型的对象。
接下来将要实现的是统一数据库访问接口和对容器框架的泛型化……