php实现装饰器(装饰器的实现)

发布时间:2022-11-08

本文目录一览:

  1. [「低门槛 手把手」python 装饰器(Decorators)原理说明](#「低门槛 手把手」python 装饰器(Decorators)原理说明)
  2. [怎么给zend framework form表单添加装饰器,小弟谢一个先! - PHP框架开发](#怎么给zend framework form表单添加装饰器,小弟谢一个先! - PHP框架开发)
  3. PHP中几种常见的开发模式
  4. php一些简单功能的实现…高手进来看看

「低门槛 手把手」python 装饰器(Decorators)原理说明

本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是,在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我们先引入2个核心操作: 在这个例子中,函数hi的形参name,默认为'world' 在函数内部,又定义了另一个函数 howdoyoudo,定义这个函数时,将形参name作为新函数的形参name2的默认值。 因此,在函数内部调用howdoyoudo()时,将以调用hi时的实参为默认值,但也可以给howdoyoudo输入其他参数。 上面的例子运行后输出结果为: 这里新定义的howdoyoudo可以称作一个“闭包”。不少关于装饰器的blog都提到了这个概念,但其实没必要给它取一个多专业的名字。我们知道闭包是 函数内的函数 就可以了 当我们进行 def 的时候,我们在做什么? 这时,hi函数,打印一个字符串,同时返回一个字符串。 但hi函数本身也是一个对象,一个可以执行的对象。执行的方式是hi()。 这里hi和hi()有本质区别, hi 代表了这个函数对象本身 hi() 则是运行了函数,得到函数的返回值。 作为对比,可以想象以下代码 此时也是b存在,可以正常使用。 我们定义2个函数,分别实现自加1, 自乘2, 再定义一个函数double_exec,内容是将某个函数调用2次 在调用double_exec时,可以将函数作为输入传进来 输出结果就是 7 27 同样,也可以将函数作为输出 输出结果为 6 10 有了以上两个核心操作,我们可以尝试构造装饰器了。 装饰器的目的: 在不修改原函数(类)定义代码的情况下,增加新的功能 试想一下,现在有一个原函数 在不修改原函数定义代码的情况下,如果想进行函数内容的添加,可以将这个函数作为一个整体,添加到这样的包裹中: 我们定义了一个my_decorator函数,这个函数进行了一种操作: 对传入的f,添加操作(运行前后增加打印),并把添加操作后的内容连同运行原函数的内容,一起传出 这个my_decorator,定义了一种增加前后打印内容的行为 调用my_decorator时,对这个行为进行了操作。 因此,new_function是一个在original_function上增加了前后打印行为的新函数 这个过程被可以被称作装饰。 这里已经可以发现,装饰器本身对于被装饰的函数是什么,是不需要考虑的。装饰器本身只定义了一种装饰行为,这个行为是通过装饰器内部的闭包函数()进行定义的。 运行装饰前后的函数,可以清晰看到装饰的效果 我们复现一下实际要用装饰器的情况,我们往往有一种装饰器,想应用于很多个函数,比如 此时,如果我们想给3个print函数都加上装饰器,需要这么做 实际调用的时候,就需要调用添加装饰器的函数名了 当然,也可以赋值给原函数名 这样至少不需要管理一系列装饰前后的函数。 同时,在不需要进行装饰的时候,需要把 全部删掉。 事实上,这样并不方便,尤其对于更复杂的装饰器来说 为此,python提供了一种简写方式 这个定义print1函数前的@my_decorator,相当于在定义完print1后,自动直接运行了 不论采用@my_decorator放在新函数前,还是显示地重写print1 = my_decorator(print1),都会存在一个问题: 装饰后的函数,名字改变了(其实不止名字,一系列的索引都改变了) 输出结果为: 这个现象的原因是,装饰行为本身,是通过构造了一个新的函数(例子中是wrap_func函数)来实现装饰这个行为的,然后把这个修改后的函数赋给了原函数名。 这样,会导致我们预期的被装饰函数的一些系统变量(比如__name__)发生了变化。 对此,python提供了解决方案: 经过这个行为后,被装饰函数的系统变量问题被解决了 输出结果为 刚才的例子都比较简单,被装饰的函数是没有参数的。如果被装饰的函数有参数,只需要在定义装饰行为时(事实上,这个才更通用),增加(*args, **kwargs)描述即可 之前的描述中可以感受到,对于例子中的装饰行为(前后加打印),函数被装饰后,本质上是调用了新的装饰函数wrap_func。 因此,如果原函数需要有输入参数传递,只需要在wrap_func(或其他任意名字的装饰函数)定义时,也增加参数输入(*args, **kwargs),并将这些参数,原封不动地传给待装饰函数f。 这种定义装饰行为的方式更具有普遍性,忘记之前的定义方式吧 我们试一下 输出 这里需要注意的是,如果按照以下的方式定义装饰器 那么以下语句将不会执行 因为装饰后实际的函数wrap_func(虽然名字被改成了原函数,系统参数也改成了原函数),运行到return f(*args, **kwargs) 的时候已经结束了 因为装饰器my_decorator本身也是可以输入的,因此,只需要在定义装饰器时,增加参数,并在后续函数中使用就可以了,比如 此时装饰器已经可以有输入参数了 输出 你可能发现,为什么不用简写版的方法了 因为以上代码会报错!! 究其原因,虽然 等价于 但是, 并不等价于 这本身和@语法有关,使用@my_decorator时,是系统在应用一个以单个函数作为参数的闭包函数。即,@是不能带参数的。 但是你应该发现了,之前的@wraps(f)不是带参数了吗?请仔细观察以下代码 通过一层嵌套,my_decorator_with_parma本质上是返回了一个参数仅为一个函数的函数(my_decorator),但因为my_decorator对my_decorator_with_parma来说是一个闭包,my_decorator_with_parma是可以带参数的。(这句话真绕) 通过以上的定义,我们再来看 可以这么理解,my_decorator_with_parma(msg='yusheng')的结果是原来的my_decorator函数,同时,因为my_decorator_with_parma可以传参,参数实际上是参与了my_decorator的(因为my_decorator对my_decorator_with_parma是闭包), my_decorator_with_parma(msg='yusheng') 全等于 一个有参数参加的my_decorator 因此,以上代码等价于有参数msg传递的 比较绕,需要理解一下,或者干脆强记这种范式: 以上范式包含函数的输入输出、装饰器的输入,可以应对大部分情况了。 实验一下: 输出 以上是一个log装饰器,利用datetime统计了函数的耗时, 并且,装饰器可以进行输出文件操作,如果给出了文件路径,则输出文件,否则就打印。 利用这个装饰器,可以灵活地进行耗时统计 不设置输出文件地址,则打印。运行结果为: 也可以输出到文件 输出结果为 同时在当前目录生成了一个test.log 文件,内容为: 以上的装饰器都是以函数形式出现的,但我们可以稍做改写,将装饰器以类的形式实现。 这个装饰器类Log 上个例子里的装饰器函数log功能是一样的,同时,这个装饰器类还可以作为基类被其他继承,进一步增加功能。 原文

怎么给zend framework form表单添加装饰器,小弟谢一个先! - PHP框架开发

$this->setDecorators(array( 'FormElements', array(array('HtmlTag', array('tag'='div', 'style'='border:1px solid #d0d0d0')), 'Form')); 这段代码会在Form标签后增加div,如: #something#

PHP中几种常见的开发模式

单例模式 $_instance必须声明为静态的私有变量 构造函数和析构函数必须声明为私有,防止外部程序new 类从而失去单例模式的意义 getInstance()方法必须设置为公有的,必须调用此方法 以返回实例的一个引用 ::操作符只能访问静态变量和静态函数 new对象都会消耗内存 使用场景:最常用的地方是数据库连接。 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。 私有的__clone()方法防止克隆对象 单例模式,使某个类的对象仅允许创建一个。构造函数private修饰, 申明一个static getInstance方法,在该方法里创建该对象的实例。如果该实例已经存在,则不创建。比如只需要创建一个数据库连接。 工厂模式 工厂模式,工厂方法或者类生成对象,而不是在代码中直接new。 使用工厂模式,可以避免当改变某个类的名字或者方法之后,在调用这个类的所有的代码中都修改它的名字或者参数。

  • 如果某个类在很多的文件中都new ClassName(),那么万一这个类的名字
  • 发生变更或者参数发生变化,如果不使用工厂模式,就需要修改每一个PHP
  • 代码,使用了工厂模式之后,只需要修改工厂类或者方法就可以了。 注册模式 注册模式,解决全局共享和交换对象。已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可。将对象注册到全局的树上。任何地方直接去访问。 策略模式 策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。 eg:假如有一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告。在传统的代码中,都是在系统中加入各种if else的判断,硬编码的方式。如果有一天增加了一种用户,就需要改写代码。使用策略模式,如果要增加一种用户类型,只需要增加一种策略就可以。其他所有的地方只需要使用不同的策略就可以。 首先声明策略的接口文件,约定了策略的包含的行为。然后,定义各个具体的策略实现类。 执行结果图: 总结: 通过以上方式,可以发现,在不同用户登录时显示不同的内容,但是解决了在显示时的硬编码的问题。如果要增加一种策略,只需要增加一种策略实现类,然后在入口文件中执行判断,传入这个类即可。实现了解耦。 实现依赖倒置和控制反转(有待理解) 通过接口的方式,使得类和类之间不直接依赖。在使用该类的时候,才动态的传入该接口的一个实现类。如果要替换某个类,只需要增加一个实现了该接口的实现类,通过修改一行代码即可完成替换。 观察者模式
  1. 观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。
  2. 场景:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
  3. 观察者模式实现了低耦合,非侵入式的通知与更新机制。 定义一个事件触发抽象类。 当某个事件发生后,需要执行的逻辑增多时,可以以松耦合的方式去增删逻辑。也就是代码中的红色部分,只需要定义一个实现了观察者接口的类,实现复杂的逻辑,然后在红色的部分加上一行代码即可。这样实现了低耦合。 装饰器模式
  4. 装饰器模式,可以动态的添加修改类的功能
  5. 一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重写实现类的方法
  6. 使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大灵活性。

php一些简单功能的实现…高手进来看看

  1. 可以用地址传值的方式获得你的链接的值,也可以直接弄一个静态的
  2. 用while循环输出那个div就可以了, 例:
$q = mysql_query("select * from news");
while ($rs = mysql_fetch_array($q)) { //$rs是一个数组
?>
<div><?php echo $rs['tilte']; ?></div>
<?php
}