abstract類,interface接口,其中關鍵字extends與implements

轉自:http://php.net/manual/zh/language.oop5.abstract.php

abstract

定義爲抽象的類不能被實例化.

任何一個類,如果它裏面至少有一個方法是被聲明爲抽象的,那麼這個類就必須被聲明爲抽象的。(如果類的前方沒有abstract聲明,就會報錯)

繼承一個抽象類的時候,子類必須定義父類中的所有抽象方法;

這些方法的訪問控制必須和父類中一樣(或者更爲寬鬆)。(即,要小於等於父類的訪問控制)

方法的調用方式必須匹配,即類型和所需參數數量必須一致。

<?php
abstract class AbstractClass
{
    // 強制要求子類定義這些方法,且被定義爲抽象的方法只是聲明瞭其調用方式(參數),不能定義其具體的功能實現。 
    abstract protected function getValue();//子類繼承的訪問控制應聲明爲受保護的或者公有的,而不能定義爲私有的
    abstract protected function prefixValue($prefix);


    abstract protected function prefixName($name);//抽象方法僅需要定義需要的參數


    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }

    public function prefixName($name) {
        return "{$name}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
    
    public function prefixName($name) {
        return "{$name}ConcreteClass2";
    }
}


class ConcreteClass extends AbstractClass
{

    public function getValue() {
        return "ConcreteClass";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass";
    }

    // 子類可以定義父類簽名中不存在的可選參數
    public function prefixName($name, $separator = ".") {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }
        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "\n";   //Mr. Pacman
echo $class->prefixName("Pacwoman"), "\n"; //Mrs. Pacwoman

$class1 = new ConcreteClass1;
$class1->printOut();                      //ConcreteClass1
echo $class1->prefixValue('FOO_') ."\n";  //FOO_ConcreteClass1

$class2 = new ConcreteClass2;
$class2->printOut();                      //ConcreteClass2
echo $class2->prefixValue('FOO_') ."\n";  //FOO_ConcreteClass2
?> 


用abstract修飾的類表示這個類是一個抽象類,用abstract修飾的方法表示這個方法是一個抽象方法。

抽象方法是隻有方法聲明,而沒有方法的實現內容。

抽象類不能被實例化,通常是將抽象方法做爲子類方法重寫使用的,且要把繼承的抽象類裏的用abstract修飾的方法都實現。

<?php
abstract class AbstractClass{
      //定義抽象方法
      abstract protected function getValue();
      //普通方法
      public function printOut(){
            echo $this->getValue();
      }
}
 
class CommonClass extends AbstractClass{
      protected function getValue(){
            return "抽象方法的實現";
      }
}
 
$class1 = new CommonClass();
$class1->printOut();


轉自:http://php.net/manual/zh/language.oop5.interfaces.php

interface

對象接口
使用接口(interface),可以指定某個類必須實現哪些方法,但不需要定義這些方法的具體內容。 
接口是通過 interface 關鍵字來定義的,就像定義一個標準的類一樣,但其中定義所有的方法都是空的。 
接口中定義的所有方法都必須是公有,這是接口的特性。 


要實現一個接口,使用 implements 操作符。類中必須實現接口中定義的所有方法,否則會報一個致命錯誤。類可以實現多個接口,用逗號來分隔多個接口的名稱。 

Note: 
實現多個接口時,接口中的方法不能有重名。 
接口也可以繼承,通過使用 extends 操作符。 
類要實現接口,必須使用和接口中所定義的方法完全一致的方式。否則會導致致命錯誤。 


常量
接口中也可以定義常量。接口常量和類常量的使用完全相同,但是不能被子類或子接口所覆蓋。 


Example #1 接口示例

<?php

// 聲明一個'iTemplate'接口
interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}


// 實現接口
// 下面的寫法是正確的
class Template implements iTemplate
{
    private $vars = array();
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }
 
        return $template;
    }
}

// 下面的寫法是錯誤的,會報錯,因爲沒有實現 getHtml():
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
    private $vars = array();
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
}
?> 


Example #2 可擴充的接口

<?php
interface a
{
    public function foo();
}

interface b extends a
{
    public function baz(Baz $baz);
}

// 正確寫法
class c implements b
{
    public function foo()
    {
    }

    public function baz(Baz $baz)
    {
    }
}

// 錯誤寫法會導致一個致命錯誤
class d implements b
{
    public function foo()
    {
    }

    public function baz(Foo $foo)
    {
    }
}
?> 


Example #3 繼承多個接口

<?php
interface a
{
    public function foo();
}

interface b
{
    public function bar();
}

interface c extends a, b
{
    public function baz();
}

class d implements c
{
    public function foo()
    {
    }

    public function bar()
    {
    }

    public function baz()
    {
    }
}
?> 


Example #4 使用接口常量

<?php

interface a

{

    const b = 'Interface constant';

}

// 輸出接口常量

echo a::b;

// 錯誤寫法,因爲常量不能被覆蓋。接口常量的概念和類常量是一樣的。

class b implements a

{

    const b = 'Class constant';

}

?> 

 

interface

interface即PHP接口,並用關鍵字implements來實現接口中方法,且必須完全實現。


抽象類和接口的區別


接口是一個特殊的抽象類,接口與抽象類大致區別如下:

1,一個子類如果implements一個接口,就必須實現接口中的所有方法(不管是否需要);如果是繼承一個抽象類,只需要實現需要的方法即可

2,如果一個接口中定義的方法名改變了,那麼所有實現次接口的子類需要同樣更新方法名,而抽象類中如果方法名改變了,其子類對應的方法名將不受影響,只是變成了一個新的方法而已

3,抽象類只能單繼承,當一個子類需要實現的功能需要集成多個父類,就必須適用接口。

interface的引入是爲了部分地提供多繼承的功能。
在interface中只需聲明方法頭,而將方法體留給實現的class來做。
這些實現的class的實例完全可以當作interface的實例來對待。
在interface之間也可以聲明爲extends(多繼承)的關係。
注意一個interface可以extends多個其他interface。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章