简介
在php中,类型的继承使用extends关键字,而且最多只能继承一个父类,php不支持多继承。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class
MyClass
{
public
$dat
= 0;
public
function
__construct(
$dat
) {
$this
->dat =
$dat
;
}
public
function
getDat() {
return
"$this->dat\n"
;
}
}
class
MySubClass
extends
MyClass
{
public
function
getDat() {
return
"dat: $this->dat\n"
;
}
}
$a
=
new
MyClass(3);
$b
=
new
MySubClass(4);
echo
$a
->getDat();
// 3
echo
$b
->getDat();
// dat: 4
|
方法覆盖
包括构造函数在内,子类可以重新定义同名的类方法以覆盖父类方法。覆盖时遵循以下规则:
1.除构造函数之外,其他函数在覆盖时,函数的参数列表必须相同
2.包括构造函数在内,方法被覆盖后,调用子类方法时并不会自动调用父类方法
3.如果父类要禁止方法被子类覆盖,可以使用final来声明方法,这时如果子类仍要覆盖父类方法,将会出错
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
|
class
MyClass
{
private
$name
=
""
;
public
$num
= 0;
public
$str
=
""
;
public
function
__construct(
$name
) {
$this
->name =
$name
;
$this
->num = 100;
$this
->str =
"none"
;
}
public
function
getName() {
return
$this
->name;
}
}
class
MySubClass
extends
MyClass
{
public
function
__construct(
$name
,
$str
) {
parent::__construct(
$name
);
// 调用父类方法
$this
->num =
"0"
;
$this
->str =
$str
;
echo
parent::getName().
"\n"
;
// 调用父类方法
}
public
function
getName() {
return
parent::getName().
"$this->str\n"
;
// 调用父类方法
}
}
$b
=
new
MySubClass(
"myName"
, true);
// myName
echo
$b
->getName();
// myName1
class
MyClass
{
final
public
function
getName() {
}
}
|
属性重定义
在子类中,可以访问父类中的public和protected属性成员,除非重定义了同名的自有属性,这时,父类中的属性将无法访问。
方法则不同,子类对方法进行覆盖后,仍然可以访问到父类方法。
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
|
class
MyClass
{
public
$a
= 1;
protected
$b
= 2;
private
$c
= 3;
public
function
f1() {
echo
"MyClass f1\n"
;
echo
"\$a:$this->a; \$b:$this->b; \$c:$this->c;\n"
;
}
protected
function
f2() {
echo
"MyClass f2\n"
;
echo
"\$a:$this->a; \$b:$this->b; \$c:$this->c;\n"
;
}
private
function
f3() {
echo
"MyClass f3\n"
;
}
}
class
MySubClass
extends
MyClass
{
public
$b
= 22;
public
$c
= 33;
public
function
f1() {
echo
"MySubClass f1\n"
;
// 继承到父类中的$a属性,直接使用
echo
"\$a:$this->a; \$b:$this->b; \$c:$this->c;\n"
;
// 调用父类中的同名方法
parent::f1();
// 继承到父类中的f2()方法,直接使用
$this
->f2();
}
// 父类的f3()是私有的,这里的定义与父类无关
public
function
f3() {
echo
"MySubClass f3\n"
;
}
}
$b
=
new
MySubClass;
$b
->f1();
echo
"\n"
;
/*
MySubClass f1
$a:1; $b:22; $c:33;
MyClass f1
$a:1; $b:22; $c:3;
MyClass f2
$a:1; $b:22; $c:3;
*/
$b
->f3();
echo
"\n"
;
/*
MySubClass f3
*/
|
重定义父类(同名)属性时,属性的可访问性可以变得更开放,但不能更严格,也就是说,父类中的public属性,不能在子类中修改为private属性。
如果通过子类对象调用父类方法,那么该父类方法在访问属性时,对于重定义了的同名属性,public和protected的属性将访问到子类版本,private属性将访问到父类版本。也可以理解为,public和protected属性可以被重定义(父类的版本被重定义,从而不存在了),而private并未被重定义(父类中的属性仍然存在,通过父类方法进行访问,与子类中是否有同名属性毫不相干)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class
MyClass
{
public
$a
= 1;
protected
$b
= 2;
private
$c
= 3;
public
function
f1() {
echo
"\$a:$this->a; \$b:$this->b; \$c:$this->c;\n"
;
}
}
class
MySubClass
extends
MyClass
{
public
$a
= 11;
// 必须为public
protected
$b
= 22;
// 必须为protected或public
private
$c
= 33;
public
function
f2() {
echo
"\$a:$this->a; \$b:$this->b; \$c:$this->c;\n"
;
}
}
$b
=
new
MySubClass;
$b
->f1();
// $a:11; $b:22; $c:3;
$b
->f2();
// $a:11; $b:22; $c:33;
|
范围解析操作符 ::
又冒号常用于访问类常量、类静态变量,也用于在方法覆盖时调用父类版本。与其搭配的还包括parent、self、static等关键字。
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
|
class
MyClass
{
const
Name0 =
"MyClass"
;
// 类常量
public
static
$id0
= 0;
// 类变量
public
function
put() {
// 将被子类覆盖的方法
echo
"MyClass put()\n"
;
}
}
class
MySubClass
extends
MyClass
{
const
Name1 =
"MySubClass"
;
public
static
$id1
= 1;
public
function
put() {
parent::put();
// 调用父类版本的对象方法
echo
parent::Name0 .
"\n"
;
// 父类常量
echo
parent::
$id0
.
"\n"
;
// 父类变量
echo
self::Name1.
"\n"
;
// 子类常量
echo
self::
$id1
.
"\n"
;
// 子类变量
echo
static
::Name1 .
"\n"
;
// 子类常理
echo
static
::
$id1
.
"\n"
;
// 子类变量
}
}
$a
=
"MyClass"
;
$ca
=
new
MyClass;
$cb
=
new
MySubClass;
$cb
->put();
echo
MyClass::Name0 .
"\n"
;
echo
MyClass::
$id0
.
"\n"
;
echo
$a
::Name0 .
"\n"
;
echo
$a
::
$id0
.
"\n"
;
echo
$ca
::Name0 .
"\n"
;
echo
$ca
::
$id0
.
"\n"
;
|
在子类中访问父类中的成员时,应避免直接使用父类类名,而应使用parent::,以免破坏父类的封装性。
final
声明为final的方法不能被子类覆盖,如果类声明为final,则此类不能被继承。
1
2
3
4
5
6
7
8
9
10
11
12
|
// 声明为final的类不能被继承
final
class
MyClass
{
private
$dat
;
public
function
__construct(
$dat
) {
$this
->dat =
$dat
;
}
// final方法不能被覆盖,不过此类已经是final类,方法无必要在声明为final了
final
public
function
getDat() {
return
$this
->dat;
}
}
|