1.关键字
1) this 关键字:用于类的内部指代当前对象。
用处:类内部访问属性或方法或常量,如$this->属性名或方法名。
2) self 关键字:self是指向类本身,也就是self是不指向任何已经实例化的对象。
用处:一般self使用来指向类中的静态变量,静态函数。
如 self::$staticVar,在类的内部,不能用$this来调用静态成员。
3) parent 关键字:
用处:在子类中调用父类中定义的方法。
如 parent::getFirst(); //调用父类的 getFirst() 方法
2. 类成员的调用
1. 普通变量/方法调用
内部调用:可使用$this->
外部实例化调用:用$e->
2. 常量(const PI) 使用时(定义或引用)直接用常量名,不能像变量一样在前面加$
内部调用:可使用self::PI;
外部实例化调用:用$e::PI
3. 静态成员(static 静态变量,静态方法)静态属性不可以由对象通过 -> 操作符来访问
内部调用:可使用self::
外部实例化调用时,用$e::
3. 控制访问
PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
public(公有,默认):公有的类成员可以在任何地方被访问。
protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
private(私有):私有的类成员则只能被其定义所在的类访问。
4. 继承
PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承,格式如下:
class Child extends Parent {
// 代码部分
}
5. 重写
如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
override是重写(覆盖)了一个方法,以实现不同的功能。一般是用于子类在继承父类时,重写(重新实现)父类中的方法。
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5. 被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
6. 静态方法不能被重写为非静态的方法(会编译出错)。
6. 重载
一般重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
多态的概念比较复杂,有多种意义的多态,一个有趣但不严谨的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。
一般,我们使用多态是为了避免在父类里大量重载引起代码臃肿且难于维护。
PHP中的"重载"与其它绝大多数面向对象语言不同。传统的"重载"是用于提供多个同名的类方法,但各方法的参数类型和个数不同。PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。我们是通过魔术方法(magic methods)来实现的。当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。详见魔术方法一节。
7. 抽象类
任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的, 抽象类要使用“abstract”关键字来修饰, 在抽象类里面可以有不是抽象的方法和成员属性。被定义为抽象的方法只是声明了其调用方式(包含或不包含参数),但是不能定义其具体的功能实现。
abstract class Demo{
var $test;
abstract function fun1();
abstract function fun2();
}
定义为抽象的类不能被实例化,只能被继承。继承一个抽象类的时候,子类必须定义父类中的所有抽象方法。
另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。
此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。在抽象类中的抽象方法仅需要定义需要的参数,在子类中可以定义父类中不存在的可选参数。
<?php
abstract class
AbstractClass
{
//
我们的抽象方法仅需要定义需要的参数
abstract protected function
prefixName
(
$name
);
}
class
ConcreteClass
extends
AbstractClass
{
//
我们的子类可以定义父类签名中不存在的可选参数
public function
prefixName
(
$name
,
$separator
=
"."
) {
if (
$name
==
"Pacman"
) {
$prefix
=
"Mr"
;
} elseif (
$name
==
"Pacwoman"
) {
$prefix
=
"Mrs"
;
} else {
$prefix
=
""
;
}
return
"
{
$prefix
}{
$separator
}
{
$name
}
"
;
}
}
$class
= new
ConcreteClass
;
echo
$class
->
prefixName
(
"Pacman"
),
"\n"
;
echo
$class
->
prefixName
(
"Pacwoman"
),
"\n"
;
?>
8. 接口
接口只是对事物的属性和行为更高层次的抽象
使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
接口中定义的所有方法都必须是公有,这是接口的特性。
在interface里面的变量默认都是public staticfinal 的。所以可以直接省略修饰符:
String param="ssm";//变量需要初始化
要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。
PHP子类只能继承自一个父类,但是可以实现多个接口,用逗号来分隔多个接口的名称。
// 声明一个'iTemplate'接口
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
9. final 关键字
如果父类中的方法被声明为 final,则子类无法覆盖该方法。
如果一个类被声明为 final,则不能被继承。
10. 静态属性和静态方法的调用
关于它们的调用(能不能调用,怎么样调用),需要弄明白了他们在内存中存放位置,这样就非常容易理解了。静态属性、方法(包括静态与非静态)在内存中,只有一个位置(而非静态属性,有多少实例化对象,就有多少个属性)。
声明类属性或方法为 static(静态),就可以不实例化类而直接访问。由于静态方法不需要通过对象即可调用,所以伪变量$this 在静态方法中不可用。
<?php
header("content-type:text/html;charset=utf-8");
class Human{
static public $name = "小妹";
public $height = 180;
static public function tell(){
echo self::$name;//静态方法调用静态属性,使用self关键词
//echo $this->height;//错。静态方法不能调用非静态属性//因为 $this代表实例化对象,而这里是类,不知道 $this 代表哪个对象
}
public function say(){
echo self::$name . "我说话了";
//普通方法调用静态属性,同样使用self关键词
echo $this->height;
}
}
$p1 = new Human();
$p1->say();
$p1->tell();//对象可以访问静态方法
echo $p1::$name;//对象访问静态属性。不能这么访问$p1->name //因为静态属性的内存位置不在对象里
Human::say();//错。say()方法有$this时出错;没有$this时能出结果 //但php5.4以上会提示
?>
结论:
(1)、静态属性不需要实例化即可调用。因为静态属性存放的位置是在类里,调用方法为"类名::属性名";
(2)、静态方法是一种不能想对象实施操作的方法,即不需要实例化即可调用。同上
(3)、静态方法不能调用非静态属性。因为非静态属性需要实例化后,存放在对象里;
(4)、静态方法可以调用非静态方法,使用 self 关键词。php里,一个方法被self:: 后,它就自动转变为静态方法;
11、类的比较
当使用比较运算符(==)比较两个对象变量时,比较的原则是:如果两个对象的属性和属性值 都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。
而如果使用全等运算符(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)。
12、对象复制
https://www.jb51.net/article/137558.htm
PHP的『引用』与『指针』与是完全不同的技术模型。使用引用并不能提高执行效率。使用引用是一件不好的事情,除了引用本身不好,并且还会使性能下降这个事实外,使用引用这种方式会使得代码难以维护。尽量避免使用引用。
13、对象克隆
对象的赋值,当一个对象把里面的数据修改了,另一个对象的数据也会跟着变化,因为赋值是相当于把对象标识符赋值了一份,而克隆并不是这样的。对象克隆会生成一个全新的对象。
在PHP的魔术方法中有一个魔术方法和PHP的克隆有关的__clone(),在复制完成时,如果在类里面定义了魔术方法__clone()方法,则新创建也就是复制生成的对象会调用这个__clone()方法,在这个方法中如果有需要可以对属性做一些变动。
14、对象序列化
在PHP中当程序执行完一个文件,就会自动的释放内存,我们在文件中创建的对象,变量等,都会消失,如果我们在一个文件创建了一个对象,在另外一个对象中想要使用这个对象,就可以使用到对象的序列化(serialize())和反序列化(unserialize())。
序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
serialize和unserialize函数(这两个是序列化和反序列化PHP中数据的常用函数)<?php
$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
$s = serialize($a); //序列化数组
echo $s; //输出结果:a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}
$o = unserialize($s); //反序列化
print_r($o); //输出结果 Array ( [a] => Apple [b] => banana [c] => Coconut )
?>
当数组值包含如双引号、单引号或冒号等字符时,它们被反序列化后,可能会出现问题。为了克服这个问题,一个巧妙的技巧是使用base64_encode和base64_decode。
$obj = array();
$s = base64_encode(serialize($obj)); //序列化
$original = unserialize(base64_decode($s)); //反序列化
但是base64编码将增加字符串的长度。为了克服这个问题,可以和gzcompress一起使用。
//定义一个用来序列化对象的函数
function my_serialize( $obj )
{
return base64_encode(gzcompress(serialize($obj)));
}
//反序列化
function my_unserialize($txt)
{
return unserialize(gzuncompress(base64_decode($txt)));
}