文章目录
面向对象程序设计的主要概念
在面向对象的程序设计(object-oriented programming,oop)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。
对象的三个主要特性
- 行为:可以对对象进行的操作
- 形态:对对象实施特定方法时对象的响应,属性等
- 表示:对象的表示相当于身份证,具体区分在相同的行为与状态下有什么不同
面向对象内容
- 类:定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。
- 对象:类的实例
- 成员变量:定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可成为对象的属性。
- 成员函数:定义在类的内部,可用于访问对象的数据。
- 继承:继承性是子类自动共享父类数据结构和方法的机智,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上进行,把这个已经存在的类所英以的内容作为自己的内容,并加入若干新的内容。
- 父类:一个类被其他类继承,可将该类成为父类、基类、超类。
- 子类:一个类继承其他类成为子类、派生类。
- 多态:多态性是指相同的操作数或函数,过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到统一消息可以产生不同的结果,这种现象成为多态性。
- 重载:同样的函数名或方法名,但是参数列表不同的情形,这样同名不同参数的函数或方法之间,互相称为重载函数或方法。
- 抽象性:抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质而忽略其他的性质。
- 封装:是指将现实世界中存在的某个客体的属性与行为绑定在一起并放进一个逻辑单元内。
- 析构函数:析构函数(destructor)与构造函数相反,当对象结束其生命周期时,系统自动执行析构函数。
下面,我们通过Student类创建几个对象:Alice,Bob,Cindy
$Alice=new Student();
$Bob=new Student();
$Cindy=new Student();
PHP类定义
类定义语法格式:
<?php
class phpClass{
var $var1;
var $var2="constant string";
function myfunc($arg1,$arg2){
函数代码;
}
}
?>
- 类的定义使用class关键字加上类名定义
- 类名后用大括号将变量和方法括起来
- 类的变量使用var来声明,可以初始化,也可以仅声明不初始化
- 函数定义类似普通函数的定义,但函数只能通过该类及其实例化对象访问
实例
<?php
class Site {
/* 成员变量 */
var $url;
var $title;
/* 成员函数 */
function setUrl($par){
$this->url = $par;//this代表自身的对象
}
function getUrl(){
echo $this->url . PHP_EOL;//换行符
}
function setTitle($par){
$this->title = $par;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
?>
PHP创建对象
类创建之后,我们可以使用new
运算符来实例化该类的对象:
$google=new Site;
实例化对象后,我们可以使用该对象调用成员方法,该对象的成员方法只能操作该对象的成员变量:
//调用成员函数设置标题和URL
$google->setSite("Google Scholar");
$google->setUrl("https://scholar.google.com.hk/?hl=en");
//调用成员获取标题和URL
$google->getTitle();
$google->getUrl();
PHP构造函数
构造函数是一种特殊的方法,主要用来在创建爱你对象时初始化对象,即为对象成员变量赋初始值,总与new
运算符一起用在创建对象的语句中。
PHP5允许开发者在一个类中定义一个方法来作为构造函数,语法格式如下:
void __construct([mixed $args[,$..]])
在上面的例子中我们就可以通过构造方法来初始化$url
和$site
这两个变量:
function __construct( $par1, $par2 ) {
$this->url = $par1;
$this->title = $par2;
}
析构函数
析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。语法格式如下:
void __destruct ( void )
<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "销毁 " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
继承
PHP使用关键字extends
来继承一个类,PHP不支持多继承,语法格式如下:
class Child extends Parent{
//代码部分
}
实例:
<?php
class Child_Site extends Site{
var $category;
function setCate(){
$this->category=$par;
}
function getCate(){
echo $this->category.PHP_EOL;//输出一个换行符
}
}
?>
方法重写
如果父类继承的方法不能满足子类要求,可以对其进行改写,这个过程叫方法的覆盖(override)或是重写。
下列实例重写了getUrl和getTitle方法:
function getUrl(){
echo $this->url.PHP_EOL;
return $this->url;
}
funciton getTitle(){
echo $this->title.PHP_EOL;
return $this->title;
}
访问控制
PHP对属性或方法的访问控制,是通过在前面添加关键public
、protected
或是private
来实现的。
- public:公有,共有的类成员可以在任何地方被访问
- protected:受保护,受保护的类成员则可以被其自身以及其子类和父类访问
- private:私有的类成员则只能被其定义所在的类访问
- 属性的访问控制
类属性必须定义为公有、受保护、私有之一,如果用var定义,则被视为公有。
<?php
/**
* Define MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private
/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// 可以对 public 和 protected 进行重定义,但 private 而不能
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // 这行能被正常执行
echo $obj2->private; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>
- 方法的访问控制
类中的方法可以被定义为公有、私有或受保护,如果没有设置关键字,则默认为公有。
接口
使用接口可以指定某个类完成某些方法,并不需要定义方法的具体实现过程。
接口是通过关键字interface
来定义的,但其中定义的所有的方法都是空的。接口中定义的所有方法都必须是公有的。
接口的实现需要使用implements
操作符,类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号,
来分隔多个接口的名称。
实例:
<?php
//声明一个名为ITemplate的接口,里面有两个方法
interface ITemplate{
public function setVariable($name,$var);
public funtion getHtml($template);
}
//实现接口
class Template Implements iTemplate{
private $vars=array();
public function setVariable($name,$var){
$this->vars[$name]=$var;
}
public funtion getHtml($template){
foreach($this-cars as $name=>$value){
$template=str_replace('{'.$name.'}',$value,$template);
}
return $template;
}
}
?>
常量
可以把在勒种始终保持不变的值定义为常量,常量在定义和使用的时候不需要使用$
符号。常量的值必须是一个定值,能是变量、类属性、数学运算的结果或是函数调用。
自PHP5.3.0起,可以用搞一个变量来动态调用类,但该变量的值不能为关键字(如self、parent、static)
实例:
<?php
class MyClass{
const constant="常量";
function showConstant(){
echo self::constant.PHP_EOL;
}
}
echo MyClass::constant.PHP_EOL;
$calssname="MyClass";
echo $classame::constant.PHP_EOL;
$class = new MyClass();
$class->showConstant();
echo $class::constant.PHP_EOL;
?>
抽象类
任何一个类如果里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。定义为抽象的类不能被实例化,被定义为抽象的方法知识声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法,另外,这些方法的访问控制必须和父类中一样(或更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或是公有的。
<?php
abstract class AbstractClass{
//强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);
//普通方法
public function printOut(){
print $this->getValue().PHP_EOL;
}
}
class ConcreteClass extends AbstractClass{
protected function getValue(){
return "ConcreteClass1";
}
public function prefixValue($prefix){
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass{
public function getValue(){
return "ConcreteClass2";
public function prefixValue($prefix){
return "{$prefix}ConcreteClass2";
}
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') . PHP_EOL;
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') . PHP_EOL;
?>
上述代码的输出结果:
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
此外,子类方法可以包含父类抽象方法中不存在的可选参数,例如,子类定义了一个可选参数,而父类抽象方法的声明里面没有,则都是可以正常运行的。
Static 关键字
声明类属性或方法为static(静态)则可以不实例化类直接访问。静态属性不能通过一个类已实例化的对象来访问,但静态方法可以。由于静态方法不需要通过对象即可调用,所以伪变量$this
在静态方法中不可用。静态方法不可以通过对象通过->
操作符来访问。
自PHP5.3.0起,可以用一个变量来动态调用类,但该变量的值不能为关键字self、parent、static。
<?php
class Foo {
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . PHP_EOL;
$foo = new Foo();
print $foo->staticValue() . PHP_EOL;
?>
输出结果
foo
foo
Final关键字
PHP5新增了一个关键字,如果父类中的方法被声明为final,则子类无法覆盖该方法,如果一个类被声明为final则不能被继承。
下面的例子就会报错:
<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called" . PHP_EOL;
}
final public function moreTesting() {
echo "BaseClass::moreTesting() called" . PHP_EOL;
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called" . PHP_EOL;
}
}
// 报错信息 Fatal error: Cannot override final method BaseClass::moreTesting()
?>
调用父类构造方法
PHP不会在子类的构造方法中自动的调用父类的构造方法,要执行父类的构造方法需要在子类的构造方法中调用parent::__construct()
.
<?php
class BaseClass {
function __construct() {
print "BaseClass 类中构造方法" . PHP_EOL;
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct(); // 子类构造方法不能自动调用父类的构造方法
print "SubClass 类中构造方法" . PHP_EOL;
}
}
class OtherSubClass extends BaseClass {
// 继承 BaseClass 的构造方法
}
// 调用 BaseClass 构造方法
$obj = new BaseClass();
// 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();
// 调用 BaseClass 构造方法
$obj = new OtherSubClass();
?>
输出结果:
BaseClass 类中构造方法
BaseClass 类中构造方法
SubClass 类中构造方法
BaseClass 类中构造方法