第5章 php高级编程-面向对象程序设计-郑阿奇
1.面向对象程序设计概念面向对象的程序设计有三个主要特征:封装、继承和多态。
1.封装
将数据和代码捆绑在一起。
2.继承
类提供了创建新类的一种方法,再借助于“继承”这一重要机制扩充了类的定义,实现了面向对象的优越性。
继承提供了创建新类的方法,这种方法就是,一个新类可以通过对已有的类进行修改或扩充来满足新类的需求。
新类共享已有类的行为,而自己还具有修改的或额 外添加的行为。因此,可以说继承的本质特征是行为共享。
从一个类继承定义的新类,将继承已有类的所有方法和属性,并且可以添加所需要的新的方法和属性。新类被称为已有类的子类,已有类称为父类,又叫基类
3.多态
不同的类对于不同的操作具有不同的行为,称为多态。多态机制使具有不同的内部结构的对象可以共享相同的外部接口,通过这种方式减少代码的复杂度。
2在PHP中创建类、属性和方法。
定义类的语法格式如下:
class classname
{
[ var $property[= value];…]
[function functionname($args)
{
//代码
}
]
}
在类中,使用关键字var来声明变量,即类的属性。使用关键字function来定义函数,即类的方法。
3.类的实例化与访问
在声明一个类后,类只存于文件中,程序不能直接调用,需要创建一个对象后才能使用,创建一个类对象的过程中类的实例化。类的实例化用new关键字,
<?php
class Ctest//定义一个类Ctest
{
var $stunumber;//声明一个属性
function add ($str)//声明一个方法
{
$this->stunumber=$str; //使用$this指针类内部的属性
echo $this->stunumber;
}
}
$obj=new Ctest; //创建Ctest类的一个对象$obj
?>
在实例化一个类时,有些类允许在实例化时接收参数,如果能够接收参数,可以使用以下代码创建对象,其中$args是所带参数:
$obj=new Ctest([$args,…]);
在对象被创建之后,可以在类的外部对该对象的属性和方法进行访问,访问的方法是在对象后面使用“->”符号加上要访问的属性和方法。
例如,创建了对象“$obj”,类中有属性“$stunumber”,要访问该属性可以使用“$obj->stunumber”,注意属性的前面没有“$”。
例如,访问Ctest类的属性和方法:
$obj->stunumber='081102';//给对象$obj的属性$stunumber赋值
echo $obj->stunumber;//输出'081102'
$obj->add('081101');//输出'081101'
4. 类的访问控制
引入了访问修饰符public、private和protected。它们可以控制属性和方法的可见性。
●public。可以在类的外部或内部进行访问。public是默认选项。
●private。私有的属性和方法,只可以在类的内部进行访问。私有的属性和方法将不会被继承。
●protected。被保护的属性和方法,只可以在类的内部和子类的内部进行访问。
例如:
<?php
class Cstu
{
public $number;
protected $name;
private $phone;
public function Stuinfo()
{
echo "学生信息";
}
}
$object=new Cstu;
$object->number="081101";
echo $object->number;//输出"081101"
$object->Stuinfo();//输出"学生信息"
$object->phone="84565879";//本语句出错,访问权限不够
?>
5.静态属性和方法
在类中还可以定义静态的属性和方法,所谓”静态”是指所定义的属性和方法与类的实例无关,只与类本身有关。静态的属性和方法一般用来包含类要封装的数据和功能,可以
所有类的实例共享。在类里面可以使用关键字static定义属性和方法.
访问静态属性和方法时需要使用到范围解析符“::”,格式如下:
classname::$attribute; //访问静态属性
classname::Cfunction([$args,…]); //访问静态方法
6.构造函数和析构函数
构造函数。在PHP 4中,在类的内部与类同名的函数都被认为是构造函数,在创建类的对象时被自动执行。而在PHP 5中,构造函数的名称为__construct,
“construct”的前面是两根下划线。如果一个类同时拥有__construct构造函数和与类名相同的函数,PHP 5将把__construct看做是构造函数。
PHP中的构造函数可以带参数,也可以不带参数。
析构函数。类的析构函数的名称是__destruct,如果在类中声明了__destruct函数,PHP将在对象被销毁前调用析构函数将对象从内存中销毁,节省服务器资源。
例如:
<?php
class Con
{
function __construct($num)
{
echo "执行构造函数$num";
}
function __destruct()
{
echo "执行析构函数";
}
}
$a=new Con('1');//输出"执行构造函数1"
$b=new Con('2');//输出"执行构造函数2"
//执行结束,最后输出"执行析构函数执行析构函数"
?>
7.类的继承
1.子类访问父类
php不支持多继承,所以一个子类只能继承一个父类。可以使用extends关键字指明类与类之间继承关系。
<?php
class A//定义父类A
{
public $a_str1;
private $a_str2="string2";
protected $a_str3="string3";
public function a_fun()
{
$this->a_str1= "string1";
}
}
class B extends A//定义子类B,继承于父类A
{
public $b_str;
public function b_fun()
{
parent::a_fun();//子类访问父类的方法
echo $this->a_str1;//子类中访问父类的public属性
$this->a_str3="str3";//子类中访问父类的protected属性
}
}
$b=new B;//创建对象$b
$b->a_fun();//调用A类的a_fun()方法
echo $b->a_str1;//输出"string1"
$b->b_fun();//访问B类的方法
?>
另外值得注意的是:
继承是单方向的,子类可以从父类中继承特性,但父类却无法从子类中继承特性。
如果子类中没有自己的构造函数,那么子类在实例化时会自动调用父类的构造函数。如果子类中有自己的构造函数,则执行自己的构造函数。
如果要在子类中调用父类的方法,除了使用“$this->”外,还可以使用parent关键字加范围解析符,如“parent::functionname()”。
建议使用后一种方法,因为前面的方法容易造成子类和父类方法结构不清。而对于父类的属性,在子类中只能使用“$this->”来访问,属性是不区分父类和子类的。
继承可以是多重的,例如,类B继承了类A,类C继承了类B,那么类C也就继承了类B和类B的父类的所有特性
2.重载
方法的重载是指在一个类中可以定义多个拥有相同名称的方法,通过参数个数和类型来区分这些方法,而PHP目前并不支持这一特性。
但可以通过类的继承,在子类中定义和父类中相同名称的方法来实现类似于方法重载的特性
<?php
class A
{
public $attribute="stringA";
function func()
{
echo "父类A";
}
}
class B extends A
{
public $attribute="stringB";
function func()
{
echo "子类B";
}
}
$b=new B;
echo $b->attribute; //输出"stringB"
$b->func(); //输出"子类B"
?>
3.使用final关键字
PHP 5引入了final关键字,在声明类时使用这个关键字,将使这个类不能被继承。例如,定义一个类A:
final class A
{
//….
}
如果类B尝试继承类A,将会提示以下错误:
Fatal error: Class B may not inherit from final class (A)
另外,如果将final关键字用于声明类中的方法,该方法将不能在任何子类中重载。
8.抽象类和接口
1.抽象类
使用关键字abstract来定义。
特点
不能被实例化。
一个抽象类中至少包含一个抽象方法,抽象方法也是由abstract关键字来定义。
抽象方法只提供了方法的声明,不提供方法的具体实现
<?php
//定义抽象类teacher
abstract class teacher
{
var $number="081101";
var $project;
abstract function shownumber();//定义抽象方法shownumber()
abstract function getproject($project);//定义抽象方法getproject()
function showproject()//在抽象类中定义普通方法showproject()
{
echo $this->project;
}
}
//定义子类stu
class stu extends teacher
{
function shownumber()//重载父类中的shownumber()方法
{
echo $this->number;
}
function getproject ($pro)//重载父类中的getproject()方法
{
$this->project= $pro;
}
}
$obj=new stu;//创建对象
$obj->shownumber();//输出"081101"
$obj->getproject("计算机");
$obj->showproject();//输出"计算机"
?>
2.接口
接口可以多重继承,接口继承使用extends关键字。接口类中定义的方法都是抽象方法。在接口中不能使用属性,但可以使用const关键字定义常量。
<?
interface stu
{
const name="tom";
function show();
function getname($name);
}
?>
接口继承用extends关键字,例如:
<?php
interface A
{
const name="";
function show();
}
interface B extends A
{
function getname();
}
?>
接口可以实例化,接口的实例化称为接口的实现。要实现一个接口需要一个子类来实现接口的所有抽象方法。
定义接口的子类使用implements关键字,另外,一个子类还可以实现多个接口,这样实现了多重继承。
<?php
interface Teacher//定义接口Teacher
{
const name="";
function getname($name);
}
interface Stu//定义接口Stu
{
function showname();
}
class Cteacher implements Teacher//定义继承接口Teacher的类Cteacher
{
var $name="";
function getname($name)
{
$this->name=$name;
}
}
class Cstu implements Teacher,Stu//定义继承接口Teacher和Stu的类Cstu
{
var $name="";
function getname($name)
{
$this->name=$name;
}
function showname()
{
echo $this->name;
}
}
$obj=new Cstu;
$obj->getname("王林");
$obj->showname();//输出"王林"
?>9.类的魔术方法 以两个下划线“__”开头的方法称魔术方法。 1. 克隆对象
__clone,可以确切的拷贝行为和一些操作<?php
class Cid
{
public $id=1;
public function __clone()
{
$this->id=$this->id+1;
}
}
$c1=new Cid;
$c2=clone $c1;
echo $c1->id;//输出1
echo $c2->id;//输出2
?>
2. 方法重载
魔术方法__call,该方法可以用于实现方法的重载
__call方法必须要有两个参数。
第一个参数包含被调用的方法名称, 第二个参数包含传递给该方法的参数数组。__call方法在类中的方法被访问时被调用
<?php
class C_call
{
function getarray($a)
{
print_r($a);
}
function getstr($str)
{
echo $str;
}
function __call($method, $array)
{
if($method=='show')
{
if(is_array($array))
$this->getarray($array);
else
$this->getstr($array);
}
}
}
$obj=new C_call;//类的实例化
$obj->show(array(1,2,3));//输出:Array ( => 1 => 2 => 3 )
$obj->show('string');//输出:'string'
?>
说明:类中没有定义show方法,此时调用__call方法,__call方法中参数$method表示被调用的方法名,参数$array表示调用的方法中的参数组成数组,如果只有一个
参数则在__call中表示为$array.
3. 访问类的属性
通常情况下,从类的外部直接访问类的属性是不建议使用的方法。这时可以使用__get和__set方法来检查和设置属性的值,这样就可以实现封装性
<?php
class classname
{
var $attribute=1;
function __get($name)
{
if($name=='attribute')
return $this->$name;
}
function __set($name,$value)
{
if($name=='attribute')
$this->$name=$value;
}
}
$a='attribute';
$obj=new classname;//初始化
echo $obj->$a;//输出1
$set=$obj->$a=10;//输出10
echo $set;
?>
4. 字符串转换
由于类创建的对象的数据类型是对象,所以不能用print或echo语句直接输出。如果要输出对象,可以在类中定义一个__toString方法,在方法中返回一个可输出的字符串
<?php
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;//输出'Hello'
?>
5. 自动加载对象
__autoload方法用于自动加载对象,它不是一个类方法,而是一个单独的函数。如果脚本中定义了__autoload函数,当使用new关键字实例化一个没有声明的类时,
这个类的名字将作为参数传递给__autoload函数,__autoload函数根据参数自动包含含有类的文件,并加载类文件中的同名类。例如:
<?php
function __autoload($name)
{
require_once $name.".php";
}
$obj=new stu();
?>
6.对象的序列化
是指将一个对象转换成字节流的形式,将序列化后的对象在一个文件或网络传输,然后反序列化为原数据。
对象序列化用serilize()函数,反序列化用unserilize()函数。在对象序列化时,如果存在魔术方法__sleep,PHP会调用__sleep方法,主要用于清除如数据提交
、关闭数据库链接等工作,并返回一个数组,该数组包含需要序列化的所有变量;在反序列化一个对象后,PHP会调用__wakeup方法,主要用于重建对象序列化时丢
失的资源。这两个魔术方法都不接收参数。
<?php
class Serialization
{
private $number= '081101';
private $name= '王林';
public function show()
{
echo $this->number;
echo $this->name;
}
function __sleep()
{
return array('number', 'name');
}
function __wakeup()
{
$this->number= '081102';
$this->name= '程明';
}
}
$test=new Serialization;//实例化
$demo=serialize($test); //序列化$test对象,将序列化后的字符保存在$demo变量中
echo $demo;//输出一串序列化后的字符串
$ntest=unserialize($demo);//反序列化
$ntest->show();//输出'081102' '程明'
?>
10 实例类型的判断
当系统很大时,往往需要判断某个对象是否是某个类创建的。这时可以使用instanceof关键字来实现。instanceof关键字是PHP 5新引入的,
它可以检查一个对象的类型,判断一个对象是否是特定类的实例,是否继承于某个类或实现某个接口。用法如下:
$var instanceof class_name;
如果变量$var是类class_name创建的对象,则返回TRUE,否则返回FALSE
<?php
class C
{
//类内容
}
$var=new C;
if($var instanceof C)
echo 'yes';//输出'yes'
else
echo 'no';
?>
11.实例-------设计一个学生管理类
设计一个学生管理类,用于获取学生信息
<html>
<head>
<title>学生管理类</title>
</head>
<body>
<form method="post">
学号:<input type="text" name="number"><br>
姓名:<input type="text" name="name"><br>
性别:<input type="radio" name="sex" value="男" checked="checked">男
<input type="radio" name="sex" value="女">女<br>
<input type="submit" name="ok" value="显示">
</form>
</body>
</html>
<?php
class student
{
private $number;
private $name;
private $sex;
function show($XH,$XM,$XB)
{
$this->number=$XH;
$this->name=$XM;
$this->sex=$XB;
echo "学号:".$this->number."<br>";
echo "姓名:".$this->name."<br>";
echo "性别:".$this->sex."<br>";
}
}
if(isset($_POST['ok']))
{
$XH=$_POST['number'];
$XM=$_POST['name'];
$XB=$_POST['sex'];
$stu=new student;
$stu->show($XH,$XM,$XB);
}
?>
页:
[1]