面向对象

面向对象已经很熟悉了,基本上就一句话总结,类是虚指,对象是类的实例

对象内容

  • 类 − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作
  • 对象 − 是类的实例
  • 成员变量 − 定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可称为对象的属性
  • 成员函数 − 定义在类的内部,可用于访问对象的数据

例如

1
2
3
$mercedes = new Car ();
$bmw = new Car ();
$audi = new Car ();

类定义

定义类通常语法格式如下:

1
2
3
4
5
6
7
8
9
10
<?php
class phpClass {
var $var1;
var $var2 = "constant string";

function myfunc ($arg1, $arg2) {
[..]
}
[..]
}

类使用class关键字后加上类名定义

类名后的一对大括号内可以定义变量和方法

类的变量使用var来声明,也可以直接初始化值

函数定义不变,但是函数只能通过实例化的类来使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Site {
/* 成员变量 */
var $url;
var $title;

/* 成员函数 */
function setUrl($par){
$this->url = $par;
}

function getUrl(){
echo $this->url . PHP_EOL;
}

function setTitle($par){
$this->title = $par;
}

function getTitle(){
echo $this->title . PHP_EOL;
}
}
  • $this 代表自身的对象
  • PHP_EOL为换行符

创建对象

创建对象使用new关键字来实例化

1
2
3
$runoob = new Site;
$taobao = new Site;
$google = new Site;

调用成员方法

1
2
3
4
5
6
7
8
9
10
// 调用成员函数,设置标题和URL
$runoob->setTitle( "菜鸟教程" );
$taobao->setTitle( "淘宝" );
$google->setTitle( "Google 搜索" );


// 调用成员函数,获取标题和URL
$runoob->getTitle();
$taobao->getTitle();
$google->getTitle();

完整演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
class Site {
/* 成员变量 */
var $url;
var $title;

/* 成员函数 */
function setUrl($par){
$this->url = $par;
}

function getUrl(){
echo $this->url . PHP_EOL;
}

function setTitle($par){
$this->title = $par;
}

function getTitle(){
echo $this->title . PHP_EOL;
}
}

$runoob = new Site;
$taobao = new Site;
$google = new Site;

// 调用成员函数,设置标题和URL
$runoob->setTitle( "菜鸟教程" );
$taobao->setTitle( "淘宝" );
$google->setTitle( "Google 搜索" );

$runoob->setUrl( 'www.runoob.com' );
$taobao->setUrl( 'www.taobao.com' );
$google->setUrl( 'www.google.com' );

// 调用成员函数,获取标题和URL
$runoob->getTitle();
$taobao->getTitle();
$google->getTitle();

$runoob->getUrl();
$taobao->getUrl();
$google->getUrl();

运行结果
1
2
3
4
5
6
菜鸟教程
淘宝
Google 搜索
www.runoob.com
www.taobao.com
www.google.com

构造函数

使用 _construct(mixed $args[,$…])来定义构造函数

1
2
3
4
function __construct( $par1, $par2 ) {
$this->url = $par1;
$this->title = $par2;
}

用法与C++一样

析构函数

使用_destructor来定义析构函数

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "销毁 " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();

析构函数如果没有特别操作可以不写,系统会自动调用终结对象生命周期

继承

使用extends关键字来继承一个类,PHP为单继承语言

1
2
3
class Child extends Parent {
// 代码部分
}

继承的类会拥有被继承类的所有函数和方法,除构造和析构函数

方法重写

如果父类继承的方法不能满足子类的需求,就可以对其进行重写,也可以称为覆盖

1
2
3
4
5
6
7
8
9
function getUrl() {
echo $this->url . PHP_EOL;
return $this->url;
}

function getTitle(){
echo $this->title . PHP_EOL;
return $this->title;
}

访问控制

和C++基本一直,都有三个访问控制

  • public 公有
  • protected 受保护
  • private 私有

属性的访问控制

如果使用var定义,则默认为公有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?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

方法的访问控制

方法和函数基本一致
没有设置关键字,则默认为公有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
/**
* Define MyClass
*/
class MyClass
{
// 声明一个公有的构造函数
public function __construct() { }

// 声明一个公有的方法
public function MyPublic() { }

// 声明一个受保护的方法
protected function MyProtected() { }

// 声明一个私有的方法
private function MyPrivate() { }

// 此方法为公有
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}

$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
$myclass->MyProtected(); // 这行会产生一个致命错误
$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行


/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// 此方法为公有
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // 这行会产生一个致命错误
}
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行

class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}

public function testPublic() {
echo "Bar::testPublic\n";
}

private function testPrivate() {
echo "Bar::testPrivate\n";
}
}

class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}

private function testPrivate() {
echo "Foo::testPrivate\n";
}
}

$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic

接口

使用interface来定义接口

与定义类的方法唯一不同的就是,在接口中的所有方法都是空的,而且必须为公有的,这是接口的特性

使用implements来实现接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

<?php

// 声明一个'iTemplate'接口
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}


// 实现接口
class Template implements iTemplate
{
private $vars = array();

public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}

public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}

return $template;
}
}

常量

可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用$符号

使用const关键字来定义常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class MyClass
{
const constant = '常量值';

function showConstant() {
echo self::constant . PHP_EOL;
}
}

echo MyClass::constant . PHP_EOL;

$classname = "MyClass";
echo $classname::constant . PHP_EOL; // 自 5.3.0 起

$class = new MyClass();
$class->showConstant();

echo $class::constant . PHP_EOL; // 自 PHP 5.3.0 起

抽象类

使用abstract关键字来定义抽象类

抽象方法只能在抽象类中定义,抽象类中可以定义非抽象的方法

被定义为抽象类,不能实例化为对象,必须通过继承来在子类中实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
abstract class AbstractClass
{
// 强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);

// 普通方法(非抽象方法)
public function printOut() {
print $this->getValue() . PHP_EOL;
}
}

class ConcreteClass1 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;

运行结果

1
2
3
4
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

static关键字

static就是静态的,使用方法基本就与C++一致,可以直接访问不实例化类

静态属性不能通过一个类已实例化的对象来访问,静态方法可以

静态属性一旦定义,值就不可以再改变,并且生命周期只有程序结束时随着程序生命周期结束而结束

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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;

运行结果

1
2
foo
foo

final关键字

如果父类中有方法被声明为final,则子类无法覆盖该方法

如果一个类被声明为final,则不能被继承

调用父类构造方法

要执行父类的构造方法,需要在子类的构造方法中调用parent::__construct()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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();

运行结果

1
2
3
4
BaseClass 类中构造方法
BaseClass 类中构造方法
SubClass 类中构造方法
BaseClass 类中构造方法

总结

1.PHP的面向对象基本与C++一致,含义也基本相同,不多说

2.调用父类的构造函数需要使用parent::__construct()

3.静态属性一旦定义,值就不可以再改变,并且生命周期只有程序结束时随着程序生命周期结束而结束

4.PHP继承时没有访问控制之分,默认为public,继承父类中除了private的所有属性和方法