📜  PHP中的面向对象编程

📅  最后修改于: 2020-10-21 05:16:47             🧑  作者: Mango


我们可以想象我们的宇宙是由不同的物体(例如,太阳,地球,月亮等)组成的。同样,我们可以想象我们的汽车是由不同的物体(例如,车轮,转向,齿轮等)组成的。同样,存在面向对象的编程概念,它们将一切都假定为一个对象,并且使用不同的对象实现软件。

面向对象的概念

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

  • -这是程序员定义的数据类型,包括本地函数和本地数据。您可以将类视为用于制作许多同类(或类)对象实例的模板。

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

  • 成员变量-这些是在类内部定义的变量。该数据对于类外部而言是不可见的,并且可以通过成员函数进行访问。创建对象后,这些变量称为对象的属性。

  • 成员函数-这些是在类内部定义的函数,用于访问对象数据。

  • 继承-当通过继承父类的现有函数定义类时,则称为继承。在此,子类将继承父类的全部或部分成员函数和变量。

  • 父类-由另一个类继承的类。这也称为基类或超类。

  • 子类-从另一个类继承的类。这也称为子类或派生类。

  • 多态性-这是一个面向对象的概念,其中相同的函数可以用于不同的目的。例如,函数名称将保持不变,但采用不同数量的参数,并且可以完成不同的任务。

  • 重载-一种多态性,其中某些或所有运算符根据其自变量的类型具有不同的实现。类似的功能也可以通过不同的实现来重载。

  • 数据抽象-隐含(摘要)实现细节的数据的任何表示形式。

  • 封装-是指我们将所有数据和成员函数封装在一起以形成对象的概念。

  • 构造函数-指一种特殊类型的函数,只要类中有对象形成,就会自动调用该函数。

  • 析构函数-指的是一种特殊类型的函数,每当对象被删除或超出范围时,该函数便会自动调用。

定义PHP类

在PHP中定义新类的一般形式如下-


这是每行的描述-

  • 特殊形式的class ,后跟要定义的类的名称。

  • 一组括号,其中包含任意数量的变量声明和函数定义。

  • 变量声明以特殊形式var开头,后跟常规的$变量名;它们也可能有一个初始分配给一个恒定值。

  • 函数定义看起来很像独立的PHP函数,但是对于类而言是本地的,将用于设置和访问对象数据。

这是一个定义Book类型的类的示例-

price = $par;
      }
      
      function getPrice(){
         echo $this->price ."
"; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title ."
"; } } ?>

变量$ this是一个特殊变量,它指向同一对象,即。本身。

用PHP创建对象

一旦定义了类,就可以根据需要创建任意数量的对象。以下是如何使用new运算符创建对象的示例。

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

在这里,我们创建了三个对象,这些对象彼此独立,并且它们将分别存在。接下来,我们将看到如何访问成员函数和处理成员变量。

调用成员函数

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

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

$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

构造函数

构造函数是一种特殊类型的函数,每当创建一个对象时,它们都会自动调用。因此,我们通过构造函数初始化许多事情,从而充分利用了这种行为。

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

析构函数

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

遗产

通过使用extends子句,PHP类定义可以选择从父类定义继承。语法如下-

class Child extends Parent {
   
}

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

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

  • 自动具有与父级相同的所有成员函数,(默认情况下)这些成员函数的工作方式与父级中的那些函数相同。

下面的示例继承Books类,并根据需求添加更多功能。

class Novel extends Books {
   var $publisher;
   
   function setPublisher($par){
      $this->publisher = $par;
   }
   
   function getPublisher(){
      echo $this->publisher. "
"; } }

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

功能覆写

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

在下面的示例中,重写getPrice和getTitle函数以返回一些值。

function getPrice() {
   echo $this->price . "
"; return $this->price; } function getTitle(){ echo $this->title . "
"; return $this->title; }

公众成员

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

  • 从声明它的类之外

  • 从声明它的类中

  • 从另一个实现该类的类中进行声明

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

私人会员

通过指定成员私有,可以将其访问权限限制为声明该成员的类。不能从继承了声明该私有成员的类的类中引用该私有成员,并且不能从该类外部访问该私有成员。

类成员可以通过使用成员的私人关键字盈设为私人。

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类由其他类使用扩展继承时,myPublicFunction()和$ driver将可见。扩展类不会知道或无法访问myPrivateFunction和$ car,因为它们被声明为私有的。

受保护的成员

受保护的属性或方法可以在声明它的类以及扩展该类的类中访问。受保护的成员在这两种类之外不可用。类成员可以由通过使用在成员的前部保护关键字保护。

这是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!");
   }
}

介面

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

从PHP5开始,可以定义一个接口,如下所示:

interface Mail {
   public function sendMail();
}

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

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

常数

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

声明一个常量很容易,就像在此版本的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声明一个抽象类,如下所示:

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

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

请注意,抽象类内部的函数定义也必须以关键字abstract开头。在非抽象类中包含抽象函数定义是不合法的。

静态关键字

将类成员或方法声明为静态使其可以访问,而无需实例化类。实例化的类对象无法访问声明为static的成员(尽管static方法可以)。

试用以下示例-

staticValue() . "\n";
?>    

最终关键字

PHP 5引入了final关键字,该关键字通过在定义的前面加上final来防止子类覆盖方法。如果类本身是最终定义的,则无法扩展。

下面的示例导致致命错误:无法覆盖最终方法BaseClass :: moreTesting()

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

调用父构造函数

与其为子类编写全新的构造函数,不如通过显式调用父类的构造函数,然后再执行实例化子类所需的任何事情来编写它。这是一个简单的例子-

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);
   }
}

在此示例中,我们有一个具有两个参数构造函数的父类(Name)和一个具有三个参数构造函数的子类(NameSub1)。 NameSub1的构造函数通过使用::语法(同时传递其两个参数)显式调用其父构造函数,然后设置一个附加字段来起作用。同样,NameSub1根据其覆盖的父函数定义其非构造函数toString()函数。

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