PHP 构造函数和析构函数
前面的第一章我们已经讲过php对象的描述,如果你不了解对象的有关术语,建议你点击这里查看:PHP 高级教程-面向对象编程(OOP)[第一章],如果你已经了解过,请继续往下阅读。
当我们创建任何类的对象时,我们需要在使用它之前设置该对象的属性。我们可以通过首先初始化对象然后设置属性的值来做到这一点,->
如果变量是使用运算符public
,或者使用变量的公共setter方法private。
要在这个步骤中创建和初始化类对象,PHP提供了一个名为Constructor的特殊方法,该方法用于通过在创建对象时分配所需的属性值来构造对象。
并且为了销毁对象,使用Destructor方法。
定义构造函数和析构函数的语法
在PHP中,我们有特殊的函数来定义类的构造函数和析构函数,它们是:__construct()
和__destruct()
。注意这是两个下划线,而不是一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php class <CLASS_NAME> { // constructor function __construct() { // initialize the object properties } // destructor function __destruct() { // clearing the object reference } } ?> |
构造函数可以接受参数,而析构函数不会有任何参数,因为析构函数的工作是销毁当前的对象引用。
PHP构造函数
让我们举个例子Person类有两个私有属性,fname
并且lname
,这个类我们将定义一个构造函数在创建对象时初始化类的属性(变量)。
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 Person { // first name of person private $fname; // last name of person private $lname; // Constructor public function __construct($fname, $lname) { echo "Initialising the object...<br/>"; $this->fname = $fname; $this->lname = $lname; } // public method to show name public function showName() { echo "My name is: " . $this->fname . "" . $this->lname; } } // creating class object $john = new Person("sky8g", ".com"); $john->showName(); ?> |
输出:
1 2 | Initialising the object... My name is sky8g.com |
虽然早些时候,我们使用->
运算符来设置变量的值或使用setter方法,但在构造函数方法的情况下,我们可以在创建对象时为变量赋值。
如果一个类有一个构造函数,那么无论何时创建该类的对象,都会调用构造函数。
PHP构造函数重载
PHP不支持函数重载,因此我们不能在类中使用构造函数的多个实现。
PHP析构函数
在PHP即将从其内存中释放任何对象之前调用PHP析构函数方法。通常,您可以在析构函数方法中关闭文件,清理资源等。我们举一个例子.
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 | <?php class Person { // first name of person private $fname; // last name of person private $lname; // Constructor public function __construct($fname, $lname) { echo "Initialising the object...<br/>"; $this->fname = $fname; $this->lname = $lname; } // Destructor public function __destruct(){ // clean up resources or do something else echo "Destroying Object..."; } // public method to show name public function showName() { echo "My name is: " . $this->fname . "" . $this->lname . "<br/>"; } } // creating class object $john = new Person("sky8g", ".com"); $john->showName(); ?> |
输出
1 2 3 | Initialising the object... My name is: sky8g.com Destroying Object... |
正如我们在上面的输出中所看到的,当PHP程序结束时,就在PHP启动释放所创建的对象之前,因此调用了析构函数方法。
析构函数方法不能接受任何参数,并且在删除对象之前调用,这在对象没有引用或PHP脚本完成执行时发生。
例如:
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 Person { // first name of person private $fname; // last name of person private $lname; // Constructor public function Person($fname, $lname) { echo "Initialising the object...<br/>"; $this->fname = $fname; $this->lname = $lname; } // public method to show name public function showName() { echo "My name is: " . $this->fname . "" . $this->lname . "<br/>"; } } // creating class object $john = new Person("sky8g", ".com"); $john->showName(); ?> |
PHP 继承
在面向对象编程中,继承使类能够使用现有类的属性和方法。通常在编码时我们遇到这样的情况:我们必须创建一个具有现有类的所有功能的新类和一些其他方法,更像是对现有类的扩展,在这种情况下,我们有两种方法1.复制所有属性和将现有类的方法放入新类中,在新类中可用使用它们,或者我2.简单地继承新类中的旧类。
困惑?我们举一个简单的例子来理解它。考虑一类Human具有基本的方法是像walk(),eat(),hear(),see()等等。现在,如果我们必须创造一个男性和女性使用的两个名字Male、Female与所有的属性和类的方法Human只适用于一些特定的功能Male和Female我们可以通过继承Humanclass in Male和Femaleclass来实现。
继承的类称为Parent类
(或超类或基类),而继承其他类的类称为Child类
(或子类或派生类)。
在上面的示例中,Human将是父类,Male并且Female将是其子类。
如果我们想要创建几个类似的类,继承是非常有用的。我们可以将公共属性和方法放在一个父类中,然后在子类中继承它。
并且为了销毁对象,使用Destructor方法。
继承类的语法
在PHP中,extendskeyword用于在定义子类时指定父类的名称。例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php class Human { // parent class code } class Male extends Human { // child class code } class Female extends Human { // child class code } ?> |
使用继承时要记住的一些要点是:
2. 子类也可以拥有自己的方法,父类不可用。
3. 子类还可以覆盖父类中定义的方法,并为其提供自己的实现。
让我们几个方法添加到我们Human班,看看我们如何能够在子类中使用它们Male和Female。
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 | <?php // parent class class Human { // public property name public $name; // public function walk public function walk() { echo $this->name. " is walking...<br/>"; } // public function see public function see() { echo $this->name. " is seeing...<br/>"; } } // child class class Male extends Human { // No code in child } // child class class Female extends Human { // No code in child } $male = new Male(); $male->name = "Adam"; $female = new Female(); $female->name = "Eve"; // calling Human class methods // check the output (hehe, pun intended) $female->walk(); $male->see(); ?> |
输出
1 2 | Eve is walking... Adam is seeing... |
从上面的代码中可以看出,两个子类都是空的,我们只继承了Human它们中的类,这允许它们访问和使用父类的成员属性和方法。
具有自己的方法和属性的子类
当子类继承父类时,它可以访问和使用父类的所有非私有成员。我们知道,但是子类有自己的成员属性和方法吗?是的,它可以有。让我们再看一个例子来看看我们如何做到这一点:
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 // parent class class Vehicle { // public property name public $name; // public function start public function start() { echo $this->name. " - Engine start...<br/>"; } // public function stop public function stop() { echo $this->name. " - Engine stop...<br/>"; } } // child class class Car extends Vehicle { public function drive() { echo "I am " . $this->name . "<br/>"; echo "Lets go on a drive..."; } } // child class class Motorcycle extends Vehicle { // motorcycle specific properties // and methods } $car = new Car(); $car->name = "Mercedes benz"; // calling parent class method $car->start(); // calling child class method $car->drive(); ?> |
输出
1 2 3 | Mercedes benz - Engine start... I am Mercedes benz Lets go on a drive... |
当一个类继承另一个类时,它的优势在于能够使用父类中定义的属性和方法而无需再次定义它们。并且也可以像任何其他普通类一样拥有自己的属性和方法。
protected
访问修饰符
我们了解了各种访问修饰符以及如何使用它们来控制类的各种属性和方法的访问。
当子类继承父类时,它只能访问和重写非私有属性和方法。但是我们不应该public
对属性使用访问修饰符,因为这样也可以从类外部访问属性。
为了只允许子类访问父类的属性和方法,我们可以使用protected
访问修饰符。
当我们定义类的任何属性或方法时,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 | <?php // parent class class Vehicle { // protected property name protected $name; // public function start public function start() { echo $this->name. " - Engine start...<br/>"; } // public function stop public function stop() { echo $this->name. " - Engine stop...<br/>"; } } // child class class Car extends Vehicle { public function drive() { // accessing name variable of Car class echo "I am " . $this->name . "<br/>"; echo "Lets go on a drive..."; } } $car = new Car(); $car->name = "Mercedes benz"; // calling parent class method $car->start(); // calling child class method $car->drive(); ?> |
输出
1 2 3 | Mercedes benz - Engine start... I am Mercedes benz Lets go on a drive... |
在上面的示例中,我们将name
变量设为protected
,尝试运行名称相同的代码private
,您将收到以下错误:
输出
1 | Notice: Undefined Property... |
覆盖父类方法
如果子类想要使用父类方法但稍有不同,该怎么办?它可以通过覆盖父类中定义的方法的定义并提供自己的定义来实现。这称为方法覆盖。
让我们举个例子来理解这个概念:
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 | <?php // parent class class Vehicle { // public property name public $name; // public method public function drive() { echo "Vehicle class drive method...<br/>"; } } // child class class Car extends Vehicle { public function drive() { echo "Car class drive method...<br/>"; } } // child class class Motorcycle extends Vehicle { public function drive() { echo "Motorcycle class drive method...<br/>"; } } $car = new Car(); $car->name = "Mercedes benz"; // calling child class method $car->drive(); $bike = new Motorcycle(); $bike->name = "Triumph Tiger"; // calling child class method $bike->drive(); ?> |
输出
1 2 | Car class drive method... Motorcycle class drive method... |
在上面的代码中,我们有一个父类命名Vehicle
和两个子类,即扩展父类Car
和Motorcycle
。在父类中,我们有一个方法drive()
,我们在子类中重写并为它提供了不同的定义。
如果您不希望任何子类覆盖父类方法,该怎么办?
如果我们需要,我们可以将父类中的方法定义为final
。
让我们看看如果我们尝试覆盖一个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 | <?php // parent class class Vehicle { // public property name public $name; // public method final public function drive() { echo "Vehicle class drive method...<br/>"; } } // child class class Car extends Vehicle { public function drive() { echo "Car class drive method...<br/>"; } } $car = new Car(); $car->name = "Mercedes benz"; // calling child class method $car->drive(); ?> |
输出
1 | Fatal error: Cannot override final method Vehicle::drive() |
下一章我们将介绍:PHP 高级教程-面向对象编程(OOP)[第三章]