PHP 类和对象
在本教程中,您将学习如何在 PHP 中编写面向对象风格的代码。
什么是面向对象编程
面向对象编程 (OOP) 是一种基于类和对象概念的编程模型。与侧重于编写对数据执行操作的过程或函数的过程编程相反,面向对象编程的重点是创建同时包含数据和函数的对象。
与传统或过程式编程风格相比,面向对象编程有几个优点。下面列出了最重要的:
- 它为程序提供了清晰的模块化结构。
- 它可以帮助您遵守"不重复自己"(DRY)原则,从而使您的代码更易于维护、修改和调试。
- 它可以用更少的代码、更短的开发时间和高度的可重用性来创建更复杂的行为。
以下部分将描述类和对象在 PHP 中的工作方式。
提示: Don't Repeat Yourself (DRY) 原则背后的理念是通过抽象出应用程序常见的代码并将它们放在一个地方并重用它们而不是重复使用来减少代码的重复。 重复它。
理解类和对象
类和对象是面向对象编程的两个主要方面。 类是自包含的、独立的变量和函数的集合,它们协同工作以执行一个或多个特定任务,而对象是类的各个实例。
类充当模板或蓝图,从中可以创建许多单独的对象。 创建单个对象时,它们会继承相同的通用属性和行为,尽管每个对象的某些属性可能具有不同的值。
例如,将班级视为房屋的蓝图。 蓝图本身不是房子,而是房子的详细平面图。 同时,一个对象就像根据该蓝图建造的实际房屋。 我们可以根据相同的蓝图建造几座相同的房屋,但每座房屋的内部可能有不同的油漆、内饰和家庭,如下图所示。
可以使用 class
关键字声明类,后跟类的名称和一对花括号 ({}
),如下例所示。
让我们创建一个名为 Rectangle.asp 的 PHP 文件并将以下示例代码放入其中,以便我们的类代码应该与程序的其余部分分开。 然后我们可以在任何需要的地方使用它,只需包含 Rectangle.asp 文件。
示例
Download<?php
class Rectangle
{
// 声明属性
public $length = 0;
public $width = 0;
// 获取周长的方法
public function getPerimeter(){
return (2 * ($this->length + $this->width));
}
// 获取面积的方法
public function getArea(){
return ($this->length * $this->width);
}
}
?>
上例中属性和方法前的public
关键字,是一个访问修饰符,表示这个属性或方法是 可从任何地方访问。 我们将在本章稍后部分了解更多相关信息。
注意:在语法上,类中的变量称为属性,而函数称为方法。 此外,类名通常以 PascalCase 编写,即每个连接的单词都以大写字母开头(例如 MyClass)。
一旦定义了一个类,就可以使用 new
关键字从该类创建对象。 类方法和属性可以通过这个对象实例直接访问。
创建另一个 PHP 文件名 test.asp 并将以下代码放入其中。
<?php
// 包含类定义
require "Rectangle.asp";
// 从 Rectangle 类创建一个新对象
$obj = new Rectangle;
// 获取对象属性值
echo $obj->length; // 0utput: 0
echo $obj->width; // 0utput: 0
// Set object properties values
$obj->length = 30;
$obj->width = 20;
// 再次读取对象属性值以显示更改
echo $obj->length; // 0utput: 30
echo $obj->width; // 0utput: 20
// 调用对象方法
echo $obj->getPerimeter(); // 0utput: 100
echo $obj->getArea(); // Output: 600
?>
箭头符号 (->
) 是一个 OOP 构造,用于访问给定对象的包含属性和方法。 而伪变量 $this
提供对调用对象的引用,即方法所属的对象。
当使用同一类的多个实例时,面向对象编程的真正威力变得显而易见,如下例所示:
<?php
// 包含类定义
require "Rectangle.asp";
// 从 Rectangle 类创建多个对象
$obj1 = new Rectangle;
$obj2 = new Rectangle;
// 调用两个对象的方法
echo $obj1->getArea(); // Output: 0
echo $obj2->getArea(); // Output: 0
// 设置 $obj1 属性值
$obj1->length = 30;
$obj1->width = 20;
// 设置 $obj2 属性值
$obj2->length = 35;
$obj2->width = 50;
// 再次调用两个对象的方法
echo $obj1->getArea(); // Output: 600
echo $obj2->getArea(); // Output: 1750
?>
正如您在上面的示例中看到的,对不同的对象调用 getArea()
方法会导致该方法对不同的数据集进行操作。 每个对象实例都是完全独立的,具有自己的属性和方法,因此可以独立操作,即使它们属于同一类。
使用构造函数和析构函数
为了使面向对象的编程更容易,PHP 提供了一些魔术方法,当对象内发生某些操作时,这些方法会自动执行。
例如,每当创建新对象时,都会自动执行魔术方法 __construct()
(称为 constructor)。 同样,当对象被销毁时,魔术方法 __destruct()
(称为 destructor)会自动执行。 一旦对象被销毁,析构函数就会清除分配给对象的所有资源。
<?php
class MyClass
{
// 构造函数
public function __construct(){
echo 'The class "' . __CLASS__ . '" was initiated!<br>';
}
// 析构函数
public function __destruct(){
echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
}
}
// 创建一个新对象
$obj = new MyClass;
// 在文件末尾输出一条消息
echo "The end of the file is reached.";
?>
上例中的 PHP 代码将产生以下输出:
The end of the file is reached.
The class "MyClass" was destroyed.
脚本结束时会自动调用析构函数。 但是,要显式触发析构函数,您可以使用 PHP unset()
函数销毁对象,如下所示:
<?php
class MyClass
{
// 构造函数
public function __construct(){
echo 'The class "' . __CLASS__ . '" was initiated!<br>';
}
// 析构函数
public function __destruct(){
echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
}
}
// 创建一个新对象
$obj = new MyClass;
// 销毁对象
unset($obj);
// 在文件末尾输出一条消息
echo "The end of the file is reached.";
?>
现在,上面示例中的 PHP 代码将产生以下输出:
The class "MyClass" was destroyed.
The end of the file is reached.
提示: PHP 会在脚本完成时自动清理执行期间分配的所有资源,例如 关闭数据库连接、销毁对象等。
注意: __CLASS__
是一个魔术常量,其中包含它所在的类的名称 正在发生。 它是空的,如果它发生在类之外。
通过继承扩展类
类可以使用 extends
关键字继承另一个类的属性和方法。 这种可扩展性的过程称为继承。 这可能是使用面向对象编程模型最有力的原因。
<?php
// 包含类定义
require "Rectangle.asp";
// 基于现有类定义一个新类
class Square extends Rectangle
{
// 测试矩形是否也是正方形的方法
public function isSquare(){
if($this->length == $this->width){
return true; // Square
} else{
return false; // Not a square
}
}
}
// 从 Square 类创建一个新对象
$obj = new Square;
// 设置对象属性值
$obj->length = 20;
$obj->width = 20;
// 调用对象方法
if($obj->isSquare()){
echo "The area of the square is ";
} else{
echo "The area of the rectangle is ";
};
echo $obj->getArea();
?>
上例中的 PHP 代码将产生以下输出:
正如您在上面的示例中看到的,即使 Square 的类定义没有明确包含 getArea()
方法和 $length
和 $width
属性,Square 类的实例也可以使用它们,因为它们继承自 父矩形类。
提示: 由于子类是从父类派生的,因此也称为派生类,其父类称为基类。
控制属性和方法的可见性
使用类时,您甚至可以使用 可见性关键字 限制对其属性和方法的访问,以获得更好的控制。 共有三个可见性关键字(从最可见到最不可见): public
, protected
, private
,它决定如何以及从何处访问和修改属性和方法。
- public — 公共属性或方法可以在任何地方访问,无论是在类内部还是外部。 这是 PHP 中所有类成员的默认可见性。
- protected — 受保护的属性或方法只能从类本身或子类或继承类(即扩展该类的类)中访问。
- private — 私有属性或方法只能从定义它的类中访问。 即使是子类或继承类也无法访问私有属性或方法。
以下示例将向您展示这种可见性的实际工作原理:
示例
Download<?php
// 类定义
class Automobile
{
// 声明属性
public $fuel;
protected $engine;
private $transmission;
}
class Car extends Automobile
{
// 构造函数
public function __construct(){
echo 'The class "' . __CLASS__ . '" was initiated!<br>';
}
}
// 从 Automobile 类创建一个对象
$automobile = new Automobile;
// 尝试设置 $automobile 对象属性
$automobile->fuel = 'Petrol'; // ok
$automobile->engine = '1500 cc'; // fatal error
$automobile->transmission = 'Manual'; // fatal error
// 从 Car 类创建一个对象
$car = new Car;
// 尝试设置 $car 对象属性
$car->fuel = 'Diesel'; // ok
$car->engine = '2200 cc'; // fatal error
$car->transmission = 'Automatic'; // undefined
?>
静态属性和方法
除了可见性之外,属性和方法也可以声明为 static
,这使得它们无需类的实例化即可访问。 可以使用范围解析运算符 (::
) 访问静态属性和方法,如下所示:ClassName::$property
和 ClassName::method()
.
尽管可以使用静态方法,但不能通过该类的对象访问声明为静态的属性,如下例所示:
示例
Download<?php
// 类定义
class HelloClass
{
// 声明一个静态属性
public static $greeting = "Hello World!";
// 声明一个静态方法
public static function sayHello(){
echo self::$greeting;
}
}
// 尝试直接访问静态属性和方法
echo HelloClass::$greeting; // Output: Hello World!
HelloClass::sayHello(); // Output: Hello World!
// 尝试通过对象访问静态属性和方法
$hello = new HelloClass;
echo $hello->greeting; // Strict Warning
$hello->sayHello(); // Output: Hello World!
?>
上例中的关键字 self
表示"当前类"。 它的前面永远不会有美元符号 ($
),后面总是跟 ::
运算符(例如 self::$name
)。
a1 关键字与 self
关键字不同,this
表示"当前对象"或"类的当前实例"。this
关键字前面总是有一个美元符号 ($
),后面是 ->
运算符(例如 $this->name
)。
注意: 由于可以在没有类实例(即对象)的情况下调用静态方法,因此伪变量 $this
在声明为静态的方法中不可用。
我们希望您现在已经了解了面向对象编程的基本概念。 您将在 PHP 和 MySQL 数据库部分找到更多关于 OOP 的示例。