php学习笔记2016.1
基本类型 PHP是一种弱类型语言。
PHP类型检查函数 is_bool() is_integer() is_double() is_string() is_object() is_array() is_resource() is_null()
继承 继承是从一个基类得到一个或多个派生系类的机制。 继承自另一个类的类被称为该类的子类。 子类可以增加父类(也称超类,superclass)之外新的功能,因此子类也被称为扩展。
构造方法和继承 句柄(handle) php为此提供了parent关键字 parent ::__construct() 意为“调用父类的__construct()方法”
public private protected 管理类的访问 若使用旧的var关键字,方法和属性默认设置为public.
在任何地方都可以访问public属性和方法。
只能在当前类忠才能访问private方法或属性,及时在子类中叶不能访问。
可以在当前类或者子类中访问protected方法或属性,其他外部代码无权访问。
访问方法 比较好的做法是不要容许直接访问属性,而是提供方法来取得需要的值,这样的方法被称为访问方法,也可称为getter和setter.
静态方法和属性 把类当做生成对象的模板,吧对象作为活动组件,对象的方法可以被调用,对象的属性可以被访问。 面向对象编程中的实际操作都是通过类的实例(而不是类本身)完成的。类仅仅是对象的模板。
静态方法是以类作为作用域的函数。静态方法不能访问这个类忠的普通属性,因为那些属性属于一个对象,但可以访问静态属性。 static 关键字
常量属性 可以在类中定义常量属性。和全局常量一样,类常量一旦设置后就不能改变。常量属性用const关键字来声明,常量不像常规属性那样以美元符号开头,按照惯例,只能用大写字母来命名常量。常量属性只包含基本数据类型的值,不能将一个对象指派给常量。像静态属性一样,只能通过类而不能通过类的实例访问常量属性。引用常量时不需要用美元符号作为前导符,如print ShopProduct :: AVAILABLE; 给已经声明过的常量赋值会引起解析错误。当需要在类的所有实例中都能访问某个属性,并且属性值无需改变时,应该使用常量。
抽象类(abstract class) 抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。子类可以继承它并且通过实现其中的抽象方法,使抽象类具体化。 可以使用abstract关键字定义一个抽象类。和普通的类一样,可以创建抽象类的方法和属性,但是实例化一个抽象类会产生错误,如一个抽象类, abstract class ShopProductWriter 现在去实例化它 $writer = new ShopProductWriter() 会提示输出严重错误:不能实例化抽象类。 创建抽象方法后,要确保所有子类中都实现了该方法, 但实现的细节可以先不确定。抽象类的每个子类都必须实现抽象类中所有的抽象方法,或者把它们自身也声明为抽象方法。 扩展类不仅仅负责简单实现抽象类中的方法,还必须重新声明方法。新的实现方法的访问控制不能比抽象方法的访问控制更严格,新的实现方法的参数个数应该和抽象方法的参数个数一样,重新生成对应的类型提示。
接口(interface) 抽象类提供了具体实现标准,而接口(interface)则是纯粹的模板。接口只能定义功能,而不包含实现的内容。接口可用关键字interface来声明。接口可以包含属性和方法声明,但是方法体为空。 例如定义一个接口
interface Chargeable{
public function getPrice();
}
接口和类非常相似。任何实现接口的类要实现接口中所定义的所有方法,否则该类必须声明为abstract。
一个类可以在声明中使用implements关键字来实现某个接口。这么做之后,实现接口的具体过程和扩展一个仅包含抽象方法的抽象类是一样的。 比如让ShopProduct类实现Chargeable接口,class ShopProduct implements Chargeable 实现多个接口可以用逗号隔开,例如Bookable是接口名 class Consultancy extends TimedService implentes Bookable, Cargeable 这样Consultancy类就实现了不止一个接口,php只支持继承自一个父类,因此extends关键字只能在一个类名之前。
延迟静态绑定: static关键字
错误处理 可以停止执行代码,简单激烈,虽然__construct 和 write() 这样的方法可以检测到错误,但是它们并不知道该如何处理错误。 不在类中直接处理错误,而只返回某种错误标志。错误标志可以是布尔值或整数值。一些类也可以设置错误字符串或标志,让客户端代码在失败之后可以获得更多信息。
异常(exception) 异常是从php内置的Exception类(或其子类)实例化得到的特殊对象。Exception类型的对象用于存放和报告错误信息。exception类的构造方法接受两个可选参数:消息字符串和错误代码。抛出异常,可以联合使用throw关键字和Exception对象抛出异常。这会停止执行当前方法,并负责将错误返回给调用代码。 异常子类化,如果要创建用户自定义的异常类,可以从exceotion类继承,可以扩展异常类的功能,子类定义了新的异常类型,可以进行自己特有的错误处理。实际上,定义多个catch子句时,也只需一个try语句。
Final类和方法 继承为类层次(class hierarchy)内毒带来了巨大的灵活性。通过覆写类或方法,根据调用的是哪个类的实例,调用同样的类方法可以得到完全不同的结果。但有时候可能需要类或方法保持不变。如果希望类或方法完成确定不变的功能,担心覆写它会破坏这个功能,那么需要使用final关键字。 final关键字可以终止类的继承。 final类不能有子类,final方法不能被覆写。
使用拦截器interceptor
析构方法 __destruct() 它只在对象在被垃圾收集器收集前(即对象从内存中删除之前)自动调用。可以利用这个方法进行最后的清理工作,例如有一个类需要把其自身的信息写入数据库,这时可以使用__destruct方法在对象实例被删除时确保实例把自己保存到了数据库中
例如function __destruct() {
if(!empty($this->id)){
//保存数据
printf "saving person\n";
}
}
使用__clone()复制对象 clone使用“值复制”方式(by-value copy)新生成一个对象
class = CopyMe{}
$first = new CopyMe();
$second = clone $first;
//php5及以后的版本:$second和$first现在是两个不同的对象
在对象上调用clone时,可以控制复制什么。可以通过实现一个特殊的方法__clone()来达到这个目的(__两个下划线开头的方法都是PHP内置的方法)。当在一个对象上调用clone关键字时,其__clone()方法就会被自动调用。
实现__clone()方法时,要注意当前方法执行的环境。__clone()是复制得到的对象上运行的,而不是在原始对象上运行的。给Person类添加上__clone()方法:
class Person{
private $name;
private $age;
private $id;
function __construct ($name, $age) {
$this->name = $name;
$this->age = $age;
}
function __construct ($name, $age) {
$this->id = $id;
}
function __clone() {
$this->id = 0;
}
}
当在一个Person对象上调用clone时,产生了一个新的副本,并且新副本的__clone()方法会被调用。这意味着我们在__clone()中重新赋值会生效。
定义对象的字符串值 通过实现自己的 __toString()方法,可以控制输出字符串的格式。 __toString()方法应当返回一个字符串值。当把对象传递给print或echo时,会自动调用这个方法,并用方法的返回值来替代默认的输出内容。如在Person类中添加__toString()方法:
class Person{
function getName() {return "Bob";}
function getAge() {return 44;}
function __toString() {
$desc = $this->getName();
$desc = "(age".$this->getAge().")";
return $desc;
}
}
现在把Person对象打印 出来,该对象会被解析为:
$Person = new Person();
print $person;
-----------------------
Bob(age 44)
-----------------------
回调,匿名函数和闭包
PHP包和命名空间 命名空间就是一个容器,可以将类,函数和变量放在其中,在命名空间中,可以无条件地访问这些项,在命名空间之外,必须导入或引用命名空间,才能访问它所包含的项。namespace.
使用use关键字,利用该关键字,可以为当前命名空间中的其他命名空间起别名 例:
namespace main;
use com\getinstance\util;
util\Debug::helloWorld();
导入com\getinstance\util命名空间,并隐式地为其使用了别名until。没有使用前导反斜线字符作为开始。这里是从全局命名空间而不是从当前命名空间搜索要使用的参数。如果不想引用命名空间,可以导入Debug类本身:
namespace main;
use com\getinstance\util\Debug;
util\Debug::helloWorld();
之后吐过main命名空间中已经包含了Debug类,会造成命名冲突,解决方案是显式使用别名。
namespace main;
use com\getinstance\util\Debug as uDebug;
.......
......
.....
uDebug::helloWorld();
在use关键字后使用as子句,可以将别名Debug修改为uDebug。
如果打开命名空间块的时候不指定名称,那就可以进入全局空间。
使用文件系统模拟包
PEAR风格的命名方式
包含路径
自动加载
类函数和对象函数
查找类 class_exists()函数接受表示类的字符串,检查并返回布尔值。如果类存在,则返回true,否则返回false。
对象或类 有很多用于检测对象类型的基本工具。首先可以使用get_class()函数检查对象的类。它接受任何对象作为参数,并以字符串的形式返回类名。 instanceof()操作符有两个操作数,要检测的对象在关键字左边,类或借口名在右边。如果是给定类型的实例,则返回true。
类中的方法 可以使用get_class_methods()函数来得到一个类中所有的方法列表。该函数需要一个类名作为参数,返回包含类中所有方法名的数组。 print_r( get_class_methods( 'CdProduct' ) ); //CdProduct是参数类。在调用某个方法之前,先检测该方法是否存在于get_class_methods()返回的数组中,可以使用函数is_callable()和method_exists()来检查。两个函数中is_callable()更高级些,它接受字符串变量形式的方法名作为第一个参数,如果类方法存在且可被调用,则返回true。如果要检测类中的方法可否被调用,可以给函数传递一个数组而不是类方法名作为参数。数组必须包含对象或类名,以将其作为它的第一个元素,要检查的方法名作为第二个元素。如果该方法在类中存在,函数会返回true。
类属性 get_class_vars()函数接受类名作为参数,返回关联数组。在返回的数组中,属性名作为键名,属性值作为键值。
继承 get_parent_class()来找到一个类的父类。这个函数需要一个对象或类名作为参数,并且如果父类存在的话,就返回父类的名字。如果不存在这样的类,即我们检测到的类没有父类,就返回false。 也可可以使用is_subclass_of()函数检测类是否是另一个类的派生系。它需要接受一个子类对象和父类的名字。如果第二个参数是第一个参数的父类的话,该函数就返回true。 is_subclass_of() 只会告诉你类的继承关系,而不会告诉你类是否实现了一个接口。因此如果需要检测一个类是否实现了某个接口,应当使用instanceof操作符,或者可以使用一个函数,该函数式SPL(Standard PHP Library, 标准PHP类库)的一部分。class_implements()使用一个类名或一个对象引用作为参数,并且返回一个由接口名构成的数组。
方法调用
使用字符串来动态调用方法的例子
$product = getProduct(); //获得对象
$method = "getTitle"; //定义方法名
print $product->$method; //调用方法
PHP还提供call_user_func()方法来达到相同的目的。
反射API 不可缺少的类测试工具 ReflectionFuction
var_dump()和姊妹函数print_r()是检测PHP代码中数据的利器,但对于类和函数,反射API提供了更高层次的功能。
检查类 ReflectionClass::getName()返回要检查的类名。如果类已经在PHP代码中定义,ReflectionClass::isUSerDefined()方法返回true;如果是内置类,则ReflectionClass::isInsternal()返回true。 可以用ReflectionClass::isAbstract()来测试一个类是否是抽象的,用ReflectionClass::isInterface()来测试类是否是接口。如果想得到类的实例,可以用RefectionClass::isInstantiable()测试是否可行。
检查方法 就像ReflectionClass可以用于检查类一样,ReflectionMethod对象可以用于检查类中的方法。 获得ReflectionMethod对象的方法有两种:从ReflectionClass::getMethod()可接受一个方法名作为参数并返回相应的ReflectionMethod对象。
检查方法参数 反射API提供了ReflectionParameter类。要获得ReflectionParameter对象,需要Reflection Method对象的帮助。 ReflectionMethod::getParameters()方法可返回ReflectionParameter对象数组。 ReflectionParameter可以告诉你参数的名称,变量是否可以按引用传递(即方法声明前有一个&符号),还可以告诉你参数类型提示和方法是够接受空值作为参数。
面向对象设计和过程式编程
内聚(cohesion)是一个模块内部各成分之间的关联程度的度量。理想情况下,应该使各组件职责清晰,分工明确。如果代码间的关联范围太广,维护就会困难,因为你需要在修改某部分代码的同时修改相关的代码。
耦合 当系统各部分代码紧密绑在一起时,就会产生紧密耦合,这时在一个组件中的变化会迫使其他部件随之改变。紧密耦合并不是过程式代码特有的,但是过程式比较容易产生耦合问题。
正交(orthogonality)指将职责相关的组件紧紧组合在一起,而与外部系统环境隔开,保持独立。正交主张重用组件,期望不需要任何特殊配置就能把一个组件插入到新系统中。这样的组件有明确的与环境无关输入和输出。正交代码使修改变地更简单,因为修改一个实现只会影响到被改动的组件本身。更安全,bug的影响作用域只局限于它的作用域之中。
----------------------------php学习笔记2016.1