PHP 类和对象

在本教程中,你将学习如何在 PHP 中以面向对象的方式编写代码。

什么是面向对象的编程

面向对象编程(OOP)是一种基于类和对象概念的编程模型。与过程编程相反,其中重点在于编写对数据执行操作的过程或函数,在面向对象的编程中,重点在于包含数据和函数的对象的创建。

与传统或程序式编程相比,面向对象编程具有几个优点。最重要的列表如下:

  • 它为程序提供了清晰的模块化结构。
  • 它可以帮助你遵循“不要重复自己”(Don’t Repeat Yourself - DRY)原则,从而使你的代码更易于维护,修改和调试。
  • 它可以用更少的代码和更短的开发时间以及高度的可重用性来创建更复杂的行为。

以下部分将描述类和对象在 PHP 中的工作方式。

提示:过程编程风格编写的程序,意味着程序由一个或多个过程组成。然而,过程是一组编程语句,它们一起执行特定任务。

提示: 不要重复自己(DRY)原则背后的想法是通过抽象出应用程序常用的代码并将它们放在一个地方并重用它们而不是重复它来减少代码的重复。

理解类和对象

类和对象是面向对象编程的两个主要方面。类是一个独立的,独立的变量和函数集合,它们协同工作以执行一个或多个特定任务,而对象是类的单个实例。

类充当模板或蓝图,可以从中创建许多单个对象。创建单个对象时,它们会继承相同的通用属性和行为,尽管每个对象对于某些属性可能具有不同的值。

例如,将一个类视为房屋的蓝图。蓝图本身不是房子,而是房子的详细计划。然而,一个物体就像是根据该蓝图建造的实际房屋。我们可以用相同的蓝图建造几个相同的房子,但每个房子里面可能有不同的油漆,室内和家庭,如下图所示。

类对象关系图

可以使用 class 关键字声明类,后跟类的名称和一对花括号({}),如以下示例所示。

让我们创建一个名为 Rectangle.php 的 PHP 文件,并在其中放入以下示例代码,以便我们的类代码应该与程序的其余部分分开。然后我们可以通过简单地包含 Rectangle.php 文件在任何需要的地方使用它。

<?php
class Rectangle
{
    // Declare  properties
    public $length = 0;
    public $width = 0;
    
    // Method to get the perimeter
    public function getPerimeter(){
        return (2 * ($this->length + $this->width));
    }
    
    // Method to get the area
    public function getArea(){
        return ($this->length * $this->width);
    }
}
?>

public 关键字在上面的例子中的属性和方法之前,是一个访问修饰符,其指示该属性或方法是从任何地方访问。我们将在本章后面稍后详细了解这一点。

注意:从语法上讲,类中的变量称为属性,而函数称为方法。此外,类名通常用 PascalCase 编写,即每个连接的单词以大写字母开头(例如 MyClass)。

定义类后,可以使用 new 关键字从类创建对象。可以通过此对象实例直接访问类方法和属性。

创建另一个 PHP 文件名 test.php 并将以下代码放入其中。

<?php
// Include class definition
require "Rectangle.php";
 
// Create a new object from Rectangle class
$obj = new Rectangle;
 
// Get the object properties values
echo $obj->length; // 0utput: 0
echo $obj->width; // 0utput: 0
 
// Set object properties values
$obj->length = 30;
$obj->width = 20;
 
// Read the object properties values again to show the change
echo $obj->length; // 0utput: 30
echo $obj->width; // 0utput: 20
 
 
// Call the object methods
echo $obj->getPerimeter(); // 0utput: 100
echo $obj->getArea(); // Output: 600
?>

箭头符号(->)是一个 OOP 结构,用于访问给定对象的包含属性和方法。然而,伪变量 $this 提供对调用对象的引用,即该方法所属的对象。

当使用同一类的多个实例时,面向对象编程的真正力量变得明显,如以下示例所示:

<?php
// Include class definition
require "Rectangle.php";
 
// Create multiple objects from the Rectangle class
$obj1 = new Rectangle;
$obj2 = new Rectangle;
 
// Call the methods of both the objects
echo $obj1->getArea(); // Output: 0
echo $obj2->getArea(); // Output: 0
 
// Set $obj1 properties values
$obj1->length = 30;
$obj1->width = 20;
 
// Set $obj2 properties values
$obj2->length = 35;
$obj2->width = 50;
 
// Call the methods of both the objects again
echo $obj1->getArea(); // Output: 600
echo $obj2->getArea(); // Output: 1750
?>

正如你在上面的示例中所看到的, getArea() 在不同对象上调用该方法会导致该方法对不同的数据集进行操作。每个对象实例都是完全独立的,具有自己的属性和方法,因此可以独立操作,即使它们属于同一个类。

使用构造函数和析构函数

为了使面向对象的编程更容易,PHP 提供了一些在对象内发生某些操作时自动执行的魔术方法。

例如,无论何时创建新对象,都会自动执行魔术方法 __construct() (称为构造函数)。类似地,魔术方法 __destruct() (称为析构函数)在对象被销毁时自动执行。一旦对象被销毁,析构函数就会清除分配给对象的所有资源。

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
    
    // Destructor
    public function __destruct(){
        echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Output a message at the end of the file
echo "The end of the file is reached.";
?>

上例中的 PHP 代码将产生以下输出:

The class "MyClass" was initiated!  

The end of the file is reached.

The class "MyClass" was destroyed. 

脚本结束时会自动调用析构函数。但是,要显式触发析构函数,可以使用 PHP unset() 函数销毁对象,如下所示:

<?php
class MyClass
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
    
    // Destructor
    public function __destruct(){
    echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
    }
}
 
// Create a new object
$obj = new MyClass;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo "The end of the file is reached.";
?>

现在,上面示例中的 PHP 代码将生成以下输出:

  The class "MyClass" was initiated!
  The class "MyClass" was destroyed.
  The end of the file is reached. 

提示: PHP 会在脚本完成时自动清理执行期间分配的所有资源,例如关闭数据库连接,销毁对象等。

注意: __CLASS__ 是一个魔术常量,它包含发生它的类的名称。如果它发生在类外部,它将会是空的。

通过继承扩展类

类可以使用 extends 关键字继承另一个类的属性和方法。这个可扩展性过程称为继承。这可能是使用面向对象编程模型背后最有力的原因。

<?php
// Include class definition
require "Rectangle.php";
 
// Define a new class based on an existing class
class Square extends Rectangle
{   
    // Method to test if the rectangle is also a square
    public function isSquare(){
        if($this->length == $this->width){
            return true; // Square
        } else{
            return false; // Not a square
        }
    }
}
 
// Create a new object from Square class
$obj = new Square;
 
// Set object properties values
$obj->length = 20;
$obj->width = 20;
 
// Call the object methods
if($obj->isSquare()){
    echo "The area of the square is ";
} else{
    echo "The area of the rectangle is ";
};
echo $obj->getArea();
?>

上例中的 PHP 代码将产生以下输出:

  The area of the square is 400
 

正如你可以在上面的例子中看到,虽然广场的类定义不明确包含 getArea() 的方法,也不是 $length$width 财产,Square 类的实例可以使用它们,因为它们从父 Rectangle 类继承。

提示: 由于子类是从父类派生的,因此它也称为派生类,其父类称为基类。

控制属性和方法的可见性

使用类时,你甚至可以使用可见性关键字限制对其属性和方法的访问,以实现更好的控制。有三种能见度关键字(从最可见的至少可见): , publicprotectedprivate 其确定的属性和方法的方式和从那里可以访问和修改。

  • public - 可以在课堂内外的任何地方访问公共财产或方法。这是 PHP 中所有类成员的默认可见性。
  • protected - 受保护的属性或方法只能在类本身内或子类或继承类(即扩展该类的类)中访问。
  • private - 私有属性或方法只能在定义它的类中访问。即使是子类或继承的类也无法访问私有属性或方法。

以下示例将向你展示此可见性实际如何工作:

<?php
// Class definition
class Automobile
{
    // Declare  properties
    public $fuel;
    protected $engine;
    private $transmission;
}
class Car extends Automobile
{
    // Constructor
    public function __construct(){
        echo 'The class "' . __CLASS__ . '" was initiated!<br>';
    }
}
 
// Create an object from Automobile class
$automobile = new Automobile;
 
// Attempt to set $automobile object properties
$automobile->fuel = 'Petrol'; // ok
$automobile->engine = '1500 cc'; // fatal error
$automobile->transmission = 'Manual'; // fatal error
 
// Create an object from Car class
$car = new Car;
 
// Attempt to set $car object properties
$car->fuel = 'Diesel'; // ok
$car->engine = '2200 cc'; // fatal error
$car->transmission = 'Automatic'; // undefined
?>

静态属性和方法

除了知名度,属性和方法,也可以声明为 static ,这使得他们无需类的实例访问。可以使用范围解析运算符(::) 来访问静态属性和方法,如下所示: ClassName::$propertyClassName::method()

声明为静态属性不能经由类,但是一个静态方法可以是的对象来访问,如在下面的例子所示:

<?php
// Class definition
class HelloClass
{
    // Declare a static property
    public static $greeting = "Hello World!";
    
    // Declare a static method
    public static function sayHello(){
        echo self::$greeting;
    }
}
// Attempt to access static property and method directly
echo HelloClass::$greeting; // Output: Hello World!
HelloClass::sayHello(); // Output: Hello World!
 
// Attempt to access static property and method via object
$hello = new HelloClass;
echo $hello->greeting; // Strict Warning
$hello->sayHello(); // Output: Hello World!
?>

上例中的关键字 self 表示“当前类”。它永远不会以美元符号($)开头,并且始终跟随 :: 运算符(例如 self::$name)。

所述 self 关键字是从不同 this ,意思是“当前对象”或“一类的当前实例”关键字。的 this 关键字总是由一个美元符号前面($)和随后 -> 操作者(例如 $this->name)。

注意: 由于可以在没有类实例(即对象)的情况下调用静态方法,因此伪变量 $this 在声明为 static 的方法中不可用。

我们希望你现在已经理解了面向对象编程的基本概念。你将在 PHP 和 MySQL 数据库部分找到有关 OOP 的更多示例。