PHP面向对象


我们可以想象我们的宇宙由太阳,地球,月亮等不同的物体组成。同样,我们可以想象我们的汽车由不同的物体组成,如轮子,转向,齿轮等。同样的方式还有面向对象的编程概念,使用不同的对象实现一个软件。

面向对象的概念

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

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

  • Object - 由类定义的数据结构的单个实例。 你定义一个类,然后制作属于它的许多对象。对象也被称为实例。

  • 成员变量 - 这些是在类中定义的变量。 这些数据在课程外部是不可见的,可以通过成员函数访问。一旦对象被创建,这些变量被称为对象的属性。

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

  • 继承 - 当一个类通过继承父类的现有函数来定义时,它就被称为继承。 这里的子类将继承父类的所有或少数成员函数和变量。

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

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

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

  • 重载 - 一种多态,其中部分或全部操作符根据其参数的类型具有不同的实现。 同样的功能也可以通过不同的实现来重载。

  • 数据抽象 - 隐藏(抽象)实现细节的数据的任何表示。

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

  • 构造函数 - 指的是一种特殊类型的函数,每当有一个类的对象形成时就会自动调用它。

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

定义PHP类

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

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

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

这里是每一行的描述 -

  • 特殊的表单 ,后面跟着你想要定义的类的名字。

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

  • 变量声明以特殊形式 var 开头,后面跟着一个常规的$变量名称; 他们也可能有一个初始分配到一个常数值。

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

这里是一个定义一类书籍类型的例子 -

<?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 是一个特殊变量,它指向同一个对象即。本身。

在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 {
   <definition body>
}

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

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

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

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

class Novel extends Books {
   var $publisher;

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

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

除了继承的函数外,Novel还保留了两个额外的成员函数。

函数重载

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

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

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

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

公众成员

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

  • 来自宣称的课程外部

  • 来自宣称的阶级

  • 从另一个类中实现它所声明的类

到目前为止,我们已经看到所有成员都是公众成员。如果你想限制一个类的成员的可访问性,那么你将类成员定义为 privateprotected

私人会员

通过指定一个私有成员,你可以限制它被声明的类的可访问性。私有成员不能从继承它所声明的类的类中引用,并且不能从类外部访问。

通过使用会员的 私人 关键字infront,可以使集体成员变为私人。

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,因为它们被声明为private。

受保护的成员

受保护的属性或方法可以在声明的类中以及扩展该类的类中访问。受保护的成员不在这两种类别之外。可以使用成员前面的 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!");
   }
}

接口

定义接口是为了向实施者提供一个通用的功能名称。不同的实现者可以根据自己的需求来实现这些接口。你可以说,接口是由开发人员实现的骨架。

从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() {
   }
}

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

静态关键字

将类成员或方法声明为静态可以访问而不需要实例化类。声明为静态的成员不能使用实例化的类对象进行访问(尽管可以使用静态方法)。

试试下面的例子 -

<?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";
?>

最终关键字

PHP 5引入了最终关键字,它通过为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>";
      }
   }
?>

调用父构造函数

我们不必为子类编写一个全新的构造函数,而是通过显式调用父类的构造函数来编写它,然后执行任何必需的任何操作以实现子类的实例化。这是一个简单的例子 -

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的构造函数通过使用:: syntax(传递它的两个参数)显式地调用它的父构造函数,然后设置一个额外的字段。同样,NameSub1根据它所覆盖的父函数定义它的非构造函数toString()函数。

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