Php 简明教程

Object Oriented Programming in PHP

我们可以想象我们的宇宙是由不同的物体组成的,如太阳、地球、月亮等。类似地,我们可以想象我们的汽车是由不同的物体组成的,如车轮、方向盘、齿轮等。同样,还存在面向对象编程概念,该概念将所有内容都假设为对象,并使用不同的对象实现软件。

Object Oriented Concepts

在我们详细介绍之前,让我们定义与面向对象编程相关的术语。

  1. Class − 这是一个由程序员定义的数据类型,它包括本地函数和本地数据。可以将类视作一个模板,用于创建同一类型的(或类)对象的许多实例。

  2. Object - 由类定义的数据结构的单个实例。定义一个类一次,然后创建属于它的许多对象。对象也被称为实例。

  3. Member Variable − 这些是类内定义的变量。该数据对外不可见,可通过成员函数访问。一旦创建了对象,这些变量就会被调用为对象的属性。

  4. Member function − 这些是类内定义的函数,用于访问对象数据。

  5. Inheritance − 当一个类继承父类的现有函数时,该类被称为继承。在此,子类将继承父类的一些或全部成员函数和变量。

  6. Parent class − 被另一个类继承的类。这也被称为基类或超类。

  7. Child Class − 从另一个类继承的类。这也称为子类或派生类。

  8. Polymorphism − 这是一个面向对象的概念,同一个函数可用于不同的目的。例如,函数名称保持不变,但是它可以接受不同数量的参数并执行不同的任务。

  9. Overloading − 一种类型的多态,其中一些或全部操作符具有不同的实现,具体取决于它们的争论类型。同样,函数也可以通过实现不同而重载。

  10. Data Abstraction − 数据的任何表示形式,其中实现细节是隐藏的(抽象的)。

  11. Encapsulation − 指一个概念,即我们将所有数据和成员函数封装在一起以形成一个对象。

  12. Constructor − 指一个特殊类型的函数,当从类中进行对象形成时,该函数会自动被调用。

  13. Destructor − 指一个特殊类型的函数,当一个对象被删除或超出范围时,该函数会自动被调用。

Defining PHP Classes

在 PHP 中定义新类的通用格式如下 −

<?php
   class phpClass {
      var $var1;
      var $var2 = "constant string";

      function myfunc ($arg1, $arg2) {
         [..]
      }
      [..]
   }
?>

下面是每一行的说明 −

  1. 特殊格式 class ,后跟要定义的类的名称。

  2. 一个大括号,包围任意数量的变量声明和函数定义。

  3. 变量声明以特殊格式 var 开头,后跟一个常规的 $ 变量名;它们还可以将初始赋值设为常量值。

  4. 函数定义看起来很像独立的 PHP 函数,但它是类的局部函数,用于设置和访问对象数据。

Example

下面是一个示例,定义了一个 Books 类型的类 −

<?php
   class Books {
      /* Member variables */
      var $price;
      var $title;

      /* Member functions */
      function setPrice($par){
         $this->price = $par;
      }

      function getPrice(){
         echo $this->price ."<br/>";
      }

      function setTitle($par){
         $this->title = $par;
      }

      function getTitle(){
         echo $this->title ." <br/>";
      }
   }
?>

变量 $this 是一个特殊变量,它引用同个对象,即它自身。

Creating Objects in PHP

一旦定义了类,您就可以创建任意多的该类类型的对象。以下是如何使用 new 操作符创建对象的示例。

$physics = new Books;
$maths = new Books;
$chemistry = new Books;

在这里,我们创建了三个对象,这些对象相互独立且单独存在。下一步,我们将看到如何访问成员函数和处理成员变量。

Calling Member Functions

创建对象之后,您将能够调用与该对象相关联的成员函数。一个成员函数将只能处理相关对象的成员变量。

下面的示例演示了如何通过调用成员函数为这三本书设置标题和价格。

$physics->setTitle( "Physics for High School" );
$chemistry->setTitle( "Advanced Chemistry" );
$maths->setTitle( "Algebra" );

$physics->setPrice( 10 );
$chemistry->setPrice( 15 );
$maths->setPrice( 7 );

现在可以调用另一个成员函数来获取上述示例中设置的值 -

$physics->getTitle();
$chemistry->getTitle();
$maths->getTitle();
$physics->getPrice();
$chemistry->getPrice();
$maths->getPrice();

这会产生以下结果 −

Physics for High School
Advanced Chemistry
Algebra
10
15
7

Constructor Functions

构造函数是一种特殊类型的函数,它在创建对象时会自动调用。因此,通过构造函数初始化许多内容,我们可以充分利用此行为。

PHP 提供了一个名为 __construct() 的特殊函数来定义一个构造函数。您可以将任意数量的参数传递到构造函数中。

以下示例将为 Books 类创建一个构造函数,它将在创建对象时初始化该书的价格和标题。

function __construct( $par1, $par2 ) {
   $this->title = $par1;
   $this->price = $par2;
}

现在我们无需单独调用 set 函数来设置价格和标题。我们只能在创建对象时初始化这两个成员变量。查看以下示例 -

$physics = new Books( "Physics for High School", 10 );
$maths = new Books ( "Advanced Chemistry", 15 );
$chemistry = new Books ("Algebra", 7 );

/* Get those set values */
$physics->getTitle();
$chemistry->getTitle();
$maths->getTitle();

$physics->getPrice();
$chemistry->getPrice();
$maths->getPrice();

这会产生以下结果 −

Physics for High School
Advanced Chemistry
Algebra
10
15
7

Destructor

像构造函数一样,您可以使用函数 __destruct() 定义一个析构函数。您可以在析构函数中释放所有资源。

Inheritance

PHP 类定义可以使用 extends 子句从父类定义中继承,语法如下:

class Child extends Parent {
   <definition body>
}

继承的效果是子类(或子类或派生类)具有以下特征 -

  1. 自动具有父类的所有成员变量声明。

  2. 自动具有与父类相同的所有成员函数,这些函数(默认情况下)将按照它们在父类中的工作方式工作。

以下示例继承 Books 类并根据要求添加更多功能。

class Novel extends Books {
   var $publisher;

   function setPublisher($par){
      $this->publisher = $par;
   }

   function getPublisher(){
      echo $this->publisher. "<br />";
   }
}

现在,除了继承的函数之外,Novel 类还保留了两个其他成员函数。

Function Overriding

子类中的函数定义覆盖了父类中同名定义。在子类中,我们可以修改从父类继承的函数的定义。

在以下示例中,getPrice 和 getTitle 函数被覆盖以返回一些值。

function getPrice() {
   echo $this->price . "<br/>";
   return $this->price;
}

function getTitle(){
   echo $this->title . "<br/>";
   return $this->title;
}

Public Members

除非您另行指明,否则类的属性和方法均为公共的。也就是说,它们可以在三种可能的情况下进行访问 -

  1. 从声明它的类外部

  2. 从声明它的类中

  3. 从实现声明它的类的另一个类中

到目前为止,我们已经看到了所有成员作为公共成员。如果您希望限制类成员的可访问性,则可以将类成员定义为 privateprotected

Private members

通过将成员设为私有,你可以限制其对声明它的类的可访问性。私有成员无法从继承声明它的类的类中引用,也无法从类外部访问。

可以使用成员前面的 private 关键字将类成员设为私有。

class MyClass {
   private $car = "skoda";
   $driver = "SRK";

   function __construct($par) {

      // Statements here run every time
      // an instance of the class
      // is created.
   }

   function myPublicFunction() {
      return("I'm visible!");
   }

   private function myPrivateFunction() {
      return("I'm  not visible outside!");
   }
}

当 MyClass 类使用 extends 被另一个类继承时,myPublicFunction() 将可见,$driver 也将可见。扩展类不会意识到或访问 myPrivateFunction 和 $car,因为它们声明为私有。

Protected members

受保护的属性或方法在其声明所在的类以及该类的扩展类中都可以访问。受保护的成员在除了这两种类之外的类中不可用。可以使用成员前面的 protected 关键字将类成员设为受保护。

以下是 MyClass 的不同版本 −

class MyClass {
   protected $car = "skoda";
   $driver = "SRK";

   function __construct($par) {
      // Statements here run every time
      // an instance of the class
      // is created.
   }

   function myPublicFunction() {
      return("I'm visible!");
   }

   protected function myPrivateFunction() {
      return("I'm  visible in child class!");
   }
}

Interfaces

接口的定义是为了向实现者提供通用的函数名称。不同的实现者可以根据其要求来实现这些接口。你可以说,接口是开发人员实现的骨架。

从 PHP5 起,可以像这样定义接口 −

interface Mail {
   public function sendMail();
}

然后,如果另一个类实现了该接口,如下所示 −

class Report implements Mail {
   // sendMail() Definition goes here
}

Constants

常量有点像变量,因为它含有值,但实际上更像函数,因为常量是不可变的。一旦声明常量,它就不会改变。

声明常量很简单,在 MyClass 的此版本中就是如此 −

class MyClass {
   const requiredMargin = 1.7;

   function __construct($incomingValue) {

      // Statements here run every time
      // an instance of the class
      // is created.
   }
}

在此类中,requiredMargin 是一个常量。它使用关键字 const 声明,在任何情况下都不得将其更改为 1.7 以外的任何值。请注意,与变量名称不同,常量的名称没有前导 $。

Abstract Classes

抽象类是不可实例化的,只能继承。使用关键字 abstract 声明抽象类,如下所示 −

从抽象类继承时,父类的类声明中标记为 abstract 的所有方法都必须由子类定义;此外,这些方法必须使用相同的可见性定义。

abstract class MyAbstractClass {
   abstract function myAbstractFunction() {
   }
}

请注意,抽象类中的函数定义也必须以前导关键字 abstract 为前缀。在非抽象类中不能有抽象函数定义。

Static Keyword

将类成员或方法声明为 static 使它们可以在不需要实例化类的情况下对其进行访问。声明为 static 的成员无法通过实例化的类对象进行访问(虽然静态方法可以访问)。

尝试使用以下示例 −

<?php
   class Foo {
      public static $my_static = 'foo';

      public function staticValue() {
         return self::$my_static;
      }
   }

   print Foo::$my_static . "\n";
   $foo = new Foo();

   print $foo->staticValue() . "\n";
?>

Final Keyword

PHP 5 引入了 final 关键字,它通过使用 final 作为定义前缀来阻止子类覆盖方法。如果类本身被定义为 final,则无法使用其扩展。

以下示例导致致命错误:无法覆盖 final 方法 BaseClass::moreTesting()

<?php

   class BaseClass {
      public function test() {
         echo "BaseClass::test() called<br>";
      }

      final public function moreTesting() {
         echo "BaseClass::moreTesting() called<br>";
      }
   }

   class ChildClass extends BaseClass {
      public function moreTesting() {
         echo "ChildClass::moreTesting() called<br>";
      }
   }
?>

Calling parent constructors

让我们通过显式地调用父类的构造函数,然后再执行实例化子类时除了需要的所有其他操作之外的任何操作来编写它,而不是为子类编写一个全新的构造函数。这里有一个简单的示例 −

class Name {
   var $_firstName;
   var $_lastName;

   function Name($first_name, $last_name) {
      $this->_firstName = $first_name;
      $this->_lastName = $last_name;
   }

   function toString() {
      return($this->_lastName .", " .$this->_firstName);
   }
}
class NameSub1 extends Name {
   var $_middleInitial;

   function NameSub1($first_name, $middle_initial, $last_name) {
      Name::Name($first_name, $last_name);
      $this->_middleInitial = $middle_initial;
   }

   function toString() {
      return(Name::toString() . " " . $this->_middleInitial);
   }
}
In this example, we have a parent class (Name), which has a two-argument constructor, and a subclass (NameSub1), which has a three-argument constructor. The constructor of NameSub1 functions by calling its parent constructor explicitly using the

syntax (passing two of its arguments along) and then setting an additional field. Similarly, NameSub1 defines its non constructor toString() function in terms of the parent function that it overrides.

NOTE − 构造函数可以使用与类名称相同的名称来定义。它在上面的示例中被定义。