在对象中定义的变量属性,一般需要public,private,static关键字修饰,如果不加这些关键字修饰的话,需要在变量前加var关键字修饰。如下:
class Person {
public name; //定义属性名称
}
class Person {
var name; //定义属性名称
}
构造函数
在php5之前构造函数都是与类名相同的函数,在php5后构造函必须是两个下划线开始的函数,但是为了向下兼容,在php5中也可以识别与类同名的构造函数。
php5之前:
class Person {
function Perosn(){};
}
php5之后:
class Person {
function __construct(){};
}
析构函数
析构函数是在销毁一个对象之前执行一些特定的操作,如关闭文件等。当一个对象失去引用后就会自动调用析构函数。
析构函数是php5才引入的特性。析构函数的定义和构造函数一样都是以两个下划线开始的固定名称,析构函数不能带参数。如下:
class Person {
function __destruct(){};
}
对象的三大特性:
- 封装
- 继承
- 多态
封装性
封装性是通过private关键字在对象里修饰变量或者方法来完成的。被private修饰的变量和方法不能再对象外部被直接访问。如果需要对对象里private变量和方法进行操作可以通过定义对象的public方法来访问。public的变量和方法可以在对象外直接被访问。
魔术方法:__get(), __set(), __isset(), __unset()
如果类中的私有变量太多,而且还需要访问多次,我们就需要为每个私有变量设置公共接口来访问,这样导致了繁琐。php5.1.0以后为我们提供了__set(),__get()等魔术方法来解决这个问题。
当我们需要在外部直接访问私有变量时,如果类的内部实现了对该私有变量的操作,在外部我们就能直接访问。如在外部调用私有变量:
<?php
class Person {
private $name;
private $age;
function __set($propertyname,$propertyvalue){
$this->$propertyname = $propertyvalue;
}
public function say() {
echo "名称:" .$this->name. ", 年龄" .$this->age;
}
}
$p = new Person();
$p->name = "xzp"; //直接访问私有变量,系统会自动调用__set()函数
$p->age = 8; //直接访问私有变量
$p->say();
?>
__set()方法:这个方法用来为私有成员属性设置值的,有两个参数,第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。这个方法同样不用我们手工去调用,它也可以做成私有的,是在直接设置私有属性值的时候自动调用的,同样属性私有的已经被封装上 了,如果没有__set()这个方法,是不允许的,但是如果你在类里面加上了__set($propertyname, $value)这个方法,在直接给私有属性赋值的时候,就会自动调用它,把属性比如name传给$propertyname,把要赋的值“zhangsan”传给$value,通过这个方法的执行,达到赋值的目的。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。为了不传入非法的值,还可以在这个方法给做一下判断。
__get()方法:这个方法用来获取私有成员属性值的,有一个参数,参数传入你要获取的成员属性的名称,返回获取的属性值,这个方法不用我们手工的去调用,因为我们也可以把这个方法做成私有的方法,是在直接获取私有属性的时候对象自动调用的。因为私有属性已经被封装上了,是不能直接获取值的,但是如果你在类里面加上了这个方法,在使用“echo$p1->name”这样的语句直接获取值的时候就会自动调用。
__isset() 方法:在看这个方法之前我们看一下"isset()"函数的应用,isset()是测定变量是否设定用的函数,传入一个变量作为参数,如果传入的变量存在则传回true,否则传回false。
那么如果在一个对象外面使用"isset()"这个函数去测定对象里面的成员是否被设定可不可以用它呢?分两种情况,如果对象里面成员是公有的,我们就可以使用这个函数来测定成员属性,如果是私有的成员属性,这个函数就不起作用了,原因就是因为私有的被封装了,在外部不可见。那么我们就不可以在对象的外部使用"isset()"函数来测定私有成员属性是否被设定了呢?
答案是可以的,你只要在类里面加上一个"__isset()"方法就可以了,当在类外部使用"isset()"函数来测定对象里面的私有成员是否被设定时,就会自动调用类里面的"__isset()"方法了帮我们完成这样的操作,"__isset()"方法也可以做成私有的。
__unset()方法:看这个方法之前呢,我们也先来看一下"unset()"这个函数,"unset()"这个函数的作用是删除指定的变量且传回true,参数为要删除的变量。那么如果在一个对象外部去删除对象内部的成员属性用"unset()"函数可不可以呢,也是分两种情况,如果一个对象里面的成员属性是公有的,就可以使用这个函数在对象外面删除对象的公有属性,如果对象的成员属性是私有的,我使用这个函数就没有权限去删除,但同样如果你在一个对象里面加上"__unset()"这个方法,就可以在对象的外部去删除对象的私有成员属性了。
在对象里面加上了"__unset()"这个方法之后,在对象外部使用"unset()"函数删除对象内部的私有成员属性时,自动调用"__unset()"函数来帮
我们删除对象内部的私有成员属性,这个方法也可以在类的内部定义成私有的。
继承性
继承可以使软件具有开放性,可扩展性,增加代码可重用性。
php的只有单继承,没有c++的多继承。
php的继承使用extends关键字修饰,语法如下:
<?php
class Student extends Person {}
?>
在继承中存在访问类型的控制,php5支持3中访问修饰符
- public
- preotected
- private
访问修饰符的区别与联系:
private | protected | public | |
---|---|---|---|
类本身 | √ | √ | √ |
类的子类中 | √ | √ | |
所有外部成员 | √ |
private
private修饰的成员,对于同一个类中的成员访问都没有限制,但是对于该类外的是不允许修改操作的,该类的子类也不能访问。
protected
protected修饰的成员,对于该类的子类及子类的子类都有访问权限。但不能被该类的外部代码访问。
重载
因为子类继承了父类的成员和方法,子类可以重载父类的方法,当子类存在和父类的方法同名时,会把父类的方法覆盖掉,叫方法重载。
<?php
class Person {
function say() {
echo " father";
}
}
class Student extends Person {
function say(){ //重载了父类的say()方法
echo "student";
}
}
?>
php中提供了一种在子类重载的方法中调用父类被覆盖的方法。如下:
<?php
class Person {
function say() {
echo " father";
}
}
class Student extends Person {
function say(){ //重载了父类的say()方法
parent::say(); //调用父类的方法
echo "student";
}
}
?>
在继承中常和 final,static,const等关键字一起使用
final
final关键字可以加在类和类中的方法前,但不能使用final标识成员属性。
final关键字的作用:
1.使用final标识的类不能被继承,也就是说被final标识的类是最终的版本。
2.在类中被final标识的方法不能在子类中被覆盖
<?php
final class Person{}
?>
static
在类中使用static关键字修饰的成员和成员方法时属于整个类,使用该类new出来的所有对象实例共享static修饰的成员和成员变量。
因为static修饰的变量和方法属于整个类,所以可以用类名来访问。如下:
类型::静态属性成员
类型::静态属性方法()
static修饰的属性和方法不属于哪个对象,是属于类,所以不能在类中使用$this关键字,在类中需要使用self关键字来访问静态成员。如下:
self::静态属性成员
self::静态属性方法()
class Person {
static $count;
function getcount(){
return self::$count; //使用$count变量
}
}
静态方法使用的注意事项
类中的静态方法只能访问静态成员,不能访问非静态成员。非静态方法可以访问任何成员。
因为访问非静态成员需要使用$this 去引用,但是静态方法可以在没有对象实例的时候通过类名调用,没有对象实例就不存在$this,所以就不能使用非静态成员。
利用static在类的特性,我们可以实现单例模式。
单例模式
单例模式简单来说就是一个类只能创建一个对象。
因为php是脚本语言,每次访问都是一次独立执行的过程,在这个过程中一个类有一个实例就够了。比如操作数据库查询时只需要实例化一个数据库操作类就行了,并且只连接一次数据库就可以了,而不是在脚本中为了执行多条查询语句,单独的为每条语句实例化一个对象,如果这样的话效率会非常的低。所以单例模式的出现为我们很好的解决了这个问题。
<?php
class DB {
private static $obj = NULL;
private function __construct(){ //构造函数用private修饰,类不能再外部被实例化。
/*在这里完成数据库的连接操作*/
}
static function getInstance() {
if (is_null(self::$obj)){
$obj = new self(); //实例化本对象
}
return $obj;
}
function query($sql){
echo $sql;
}
}
$db = DB::getInstance(); //获得唯一的对象
$db->query("select * from user");
?>
const
虽然const和static的功能不同,但是使用的方法非常的相似。在php中定义常量是通过define()函数来完成的,但是类中的常量需要使用const关键字来声明。
在类中用const声明的常量和static修饰的静态变量的访问方式一样,都是通过类名来访问,或者在成员方法中通过self关键字访问。类中的const方法只能访问类中的const常量。const修饰的常量前面不要$符号,并且const修饰的常量不可以修改,修改会触发错误。
<?php
class Myclass {
const CONSTANT = "CONSTANT value";
function showconstant() {
echo self::CONSTANT; //在类中使用常量
}
}
echo Myclass::CONSTANT; //使用类名访问常量
$cla = new Myclass();
$cla->showconstant();
?>
多态性
- 抽象类
当一个类中的方法存在一个抽象方法,那么这个类就是抽象类。
什么是抽象方法?
抽象方法就是没有方法体的方法,并且在方法前面用abstract关键字修饰,如下:
abstract function fun1(); //没有方法体
如果一个类中存在抽象方法,那么这个类就是抽象类,这个类也必须使用abstract修饰。
在抽象类中可以存在不是抽象的成员和变量。抽象类不能实例化对象,只能被继承,继承抽象类的子类必须全部实现抽象方法,不然子类也是抽象类。抽象类里的成员和方法不能被private修饰。
abstract class person {
var name;
function getname() {
........
}
abstract function fun1();
}
- 接口
接口也是一种抽象类。在接口中只能存在常量和抽象方法。接口的声明使用interface关键字修饰
interface 接口名称 {
常量成员 //由const修饰的常量
抽象方法 //在接口的抽象方法不需要abstract修饰
}
接口和抽象类一样不能实例化对象,必须由子类继承,子类必须实现所有的抽象方法才能实例化对象。php中只能继承一个类,但是可以继承多个接口,而且接口也能继承接口。
接口继承接口使用extends关键字:
interface two extends one {
......
}
类继承接口使用implements关键字:
class 类名 extends 父类名称 implements 接口1,接口2,接口3......{
......
}
- 多态性
多态是面向对象的三大特性中除封装和继承之外的另一重要特性。它展现了动态绑定的功能,也称为“同名异式”。多态的功能可让软件在开发和维护时,达到充分的延伸性。事实上,多态最直接的定义是让具有继承关系的不同类对象,可以对相同名称的成员函数调用,产生不同反应效果。所谓多态性就是指一段程序能够处理多种类型对象的能力,在PHP中,多态值指的就是方法的重写。方法重写是指一个子类中可以重新修改父类中的某些方法,使其具有自己的特征。重写要求子类的方法和父类的方法名称相同,这可以通过声明抽象类或是接口来规范。
我们通过计算机USB设备的应用来介绍一下面向对象中的多态性,目前USB设置的种类仅我们自己用过的我想就有十几种吧。例如USB鼠标、USB键盘、USB存储设备等,这些计算机的外部设备都是通过USB接口连接到计算机以后,被计算机调用并启动运行的。也就是计算机正常运行的同时,没插入一种不同USB设备,就为计算机扩展一样功能,这正是我们所说的多态特征。那么为什么每个USB设备不一样,但都可以被计算机应用呢?那是因为每个USB设置都要遵守电脑USB接口的开发规范,都具有相同的能被计算机加载到并启用的方法,但运行各自相应的功能。这也正是我们对多态的定义,假设我们有一个主程序已经开发完成,需要后期由其他开发人员为其扩展一些功能,但需要在不改动主程序的基础上就可以加载到这些扩展的功能模块,其实也就是为程序开发一些插件。这就需要在主程序中需要为扩展的插件程序写好接口规范,然后每个插件只有按照规范去实现自己的功能,才能被主程序应用到。在计算机中应用USB设备的程序设计如下所示:
?php
//定义一个USB接口,让每个USB设备都遵守这个规范
interface USB{
function run();
}
class Computer{
//计算机类中的一个方法可以应用任何一种USB设备
function useUSB($usb){
$usb->run();
}
}
$computer =new Computer;
$computer ->useUSB(new Ukey()); //为计算机插入一个usb键盘设备,并运行
$computer ->useUSB(new Umouse()); //为计算机插入一个usb鼠标设备,并运行
$computer ->useUSB(new Ustore()); //为计算机插入一个usb存储设备,并运行
?>
<?php
//扩展一个USB键盘设备,实现usb接口
class Ukey implements USB {
function run(){
echo "运行USB键盘设备<br>";
}
}
//扩展一个USB鼠标设备,实现usb接口
class Umouse implements USB {
function run(){
echo "运行USB鼠标设备<br>";
}
}
//扩展一个USB存储设备,实现usb接口
class Ustore implements USB {
function run(){
echo "运行USB存储设备<br>";
}
}
?>
php对象常用函数
void __autoload(string 、$class);
//尝试加载未定义的类classbool class_alias(string $classname, string $alias, [bool $autoload = true]);
//为类classname创建一个别名alias autoload指定是否调用__autoload 成功返回true 失败返回falsebool class_exists(string $classname,[bool $autoload = true])
//检查类classname是否已定义 autoload指定是否调用__autoloadbool property_exists(mixed $class, string $proName);
//检查类或对象class是否存在proName属性bool method_exists(mixed $class, string $meName);
//检查类或对象class是否存在meName方法bool interface_exists(string $ifname,[bool $autoload = true]);
//检查接口ifname是否已定义 autoload指定是否调用__autoloadbool trait_exists(string $trname,[bool $autoload = true]);
//检查trait是否存在 autoload指定是否调用__autoloadstring get_class([object $obj]);
//得到对象obj的类名 如果在方法里调用则参数可选 如果不是对象返回falsestring get_parent_class([object $obj]);
//得到对象或类的父类名 如果在方法里调用则参数可选 如果不是对象且类不存在返回falsearray get_class_vars(string $classname);
在类外调用只返回公有属性和静态属性组成的关联数组;在类内调用返回所有属性组成的关联数组。array get_object_vars(object $obj);
在类外调用只返回公有属性组成的关联数组;在类内调用返回除了静态变量之外的所有属性组成的关联数组。array get_class_methods(mixed $class);
在类外调用返回公有方法和静态方法组成的数组;类内调用返回所有方法组成的数组array get_declared_classes(void);
//返回当前脚本中已定义类的名字数组array get_declared_interfaces(void);
//返回当前脚本中已定义接口的名字数组array get_declared_traits(void);
//返回所有已定义的traits的数组bool is_subclass_of(mixed $ob,string $class);
//如果对象ob所属类是类class的子类返回true