PHP类的方法与高级特性
php面向对象编程支持类的自动加载,构造函数和析构函数,对属性或方法的访问控制和抽象类
自动加载类
在 PHP 5 中, __autoload() 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载。因此,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用。
自动加载不可用于 PHP 的 CLI 交互模式。
构造函数和析构函数
构造函数
void __construct ([ mixed $args [, $... ]] )
PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
使用新标准的构造函数
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 BaseClass { function __construct() { print "In BaseClass constructor\n" ; } } class SubClass extends BaseClass { function __construct() { parent::__construct(); print "In SubClass constructor\n" ; } } class OtherSubClass extends BaseClass { // inherits BaseClass's constructor } // In BaseClass constructor $obj = new BaseClass(); // In BaseClass constructor // In SubClass constructor $obj = new SubClass(); // In BaseClass constructor $obj = new OtherSubClass(); ?> |
自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。
析构函数
void __destruct ( void )
PHP 5 析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
析构函数示例
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php class MyDestructableClass { function __construct() { print "In constructor\n" ; $this ->name = "MyDestructableClass" ; } function __destruct() { print "Destroying " . $this ->name . "\n" ; } } $obj = new MyDestructableClass(); ?> |
和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。
析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。
访问控制(可见性)
对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问。被定义为受保护的类成员则可以被其自身以及其子类和父类访问。被定义为私有的类成员则只能被其定义所在的类访问。
属性的访问控制:类属性必须定义为公有,受保护,私有之一。
属性声明
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
|
<?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
|
<?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 ?> |
其它对象的访问控制
同一个类的对象即使不是同一个实例也可以互相访问对方的私有与受保护成员。这是由于在这些对象的内部具体实现的细节都是已知的。
访问同一个对象类型的私有成员
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 Test { private $foo ; public function __construct( $foo ) { $this ->foo = $foo ; } private function bar() { echo 'Accessed the private method.' ; } public function baz(Test $other ) { // We can change the private property: $other ->foo = 'hello' ; var_dump( $other ->foo); // We can also call the private method: $other ->bar(); } } $test = new Test( 'test' ); $test ->baz( new Test( 'other' )); ?> |
以上例程会输出:
string(5) "hello"
Accessed the private method.
范围解析操作符 (::)
范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。
当在类定义之外引用到这些项目时,要使用类名。
自 PHP 5.3.0 起,可以通过变量来引用类,该变量的值不能是关键字(如 self,parent 和 static)。
在类的外部使用 :: 操作符
1
2
3
4
5
6
7
8
|
<?php class MyClass { const CONST_VALUE = 'A constant value' ; } $classname = 'MyClass' ; echo $classname ::CONST_VALUE; // 自 PHP 5.3.0 起 echo MyClass::CONST_VALUE; ?> |
self,parent 和 static 这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的。
在类定义内部使用 ::
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php class OtherClass extends MyClass { public static $my_static = 'static var' ; public static function doubleColon() { echo parent::CONST_VALUE . "\n" ; echo self:: $my_static . "\n" ; } } $classname = 'OtherClass' ; echo $classname ::doubleColon(); // 自 PHP 5.3.0 起 OtherClass::doubleColon(); ?> |
当一个子类覆盖其父类中的方法时,PHP 不会调用父类中已被覆盖的方法。是否调用父类的方法取决于子类。这种机制也作用于构造函数和析构函数,重载以及魔术方法。
调用父类的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php class MyClass { protected function myFunc() { echo "MyClass::myFunc()\n" ; } } class OtherClass extends MyClass { // 覆盖了父类的定义 public function myFunc() { // 但还是可以调用父类中被覆盖的方法 parent::myFunc(); echo "OtherClass::myFunc()\n" ; } } $class = new OtherClass(); $class ->myFunc(); ?> |
抽象类
PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。
抽象类示例
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
|
<?php abstract class AbstractClass { // 强制要求子类定义这些方法 abstract protected function getValue(); abstract protected function prefixValue( $prefix ); // 普通方法(非抽象方法) public function printOut() { print $this ->getValue() . "\n" ; } } 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_' ) . "\n" ; $class2 = new ConcreteClass2; $class2 ->printOut(); echo $class2 ->prefixValue( 'FOO_' ) . "\n" ; ?> |
以上例程会输出:
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
抽象类示例
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 abstract class AbstractClass { // 我们的抽象方法仅需要定义需要的参数 abstract protected function prefixName( $name ); } class ConcreteClass extends AbstractClass { // 我们的子类可以定义父类签名中不存在的可选参数 public function prefixName( $name , $separator = "." ) { if ( $name == "Pacman" ) { $prefix = "Mr" ; } elseif ( $name == "Pacwoman" ) { $prefix = "Mrs" ; } else { $prefix = "" ; } return "{$prefix}{$separator} {$name}" ; } } $class = new ConcreteClass; echo $class ->prefixName( "Pacman" ), "\n" ; echo $class ->prefixName( "Pacwoman" ), "\n" ; ?> |
以上例程会输出:
Mr. Pacman
Mrs. Pacwoman
匿名类
PHP 7 开始支持匿名类。 匿名类很有用,可以创建一次性的简单对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php // PHP 7 之前的代码 class Logger { public function log( $msg ) { echo $msg ; } } $util ->setLogger( new Logger()); // 使用了 PHP 7+ 后的代码 $util ->setLogger( new class { public function log( $msg ) { echo $msg ; } }); |
可以传递参数到匿名类的构造器,也可以扩展(extend)其他类、实现接口(implement interface),以及像其他普通的类一样使用 trait:
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php class SomeClass {} interface SomeInterface {} trait SomeTrait {} var_dump( new class (10) extends SomeClass implements SomeInterface { private $num ; public function __construct( $num ) { $this ->num = $num ; } use SomeTrait; }); |
以上例程会输出:
object(class@anonymous)#1 (1) {
["Command line code0x104c5b612":"class@anonymous":private]=>
int(10)
}
匿名类被嵌套进普通 Class 后,不能访问这个外部类(Outer class)的 private(私有)、protected(受保护)方法或者属性。 为了访问外部类(Outer class)protected 属性或方法,匿名类可以 extend(扩展)此外部类。 为了使用外部类(Outer class)的 private 属性,必须通过构造器传进来:
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
|
<?php class Outer { private $prop = 1; protected $prop2 = 2; protected function func1() { return 3; } public function func2() { return new class ( $this ->prop) extends Outer { private $prop3 ; public function __construct( $prop ) { $this ->prop3 = $prop ; } public function func3() { return $this ->prop2 + $this ->prop3 + $this ->func1(); } }; } } echo ( new Outer)->func2()->func3(); |
以上例程会输出:
6
相关推荐
深度学习 -- 损失函数
深度残差网络(Deep Residual Networks (ResNets))
深度学习 -- 激活函数
神经网络训练 -- 调整学习速率
生成对抗网络(GAN)改进与发展
生成对抗网络(GAN)优点与缺点
生成对抗网络(GAN)的训练
生成对抗网络(GAN)基本原理
生成模型与判别模型