2011-10-03 84 views
96

有沒有什麼辦法可以在PHP中定義抽象類屬性?PHP抽象屬性

abstract class Foo_Abstract { 
    abstract public $tablename; 
} 

class Foo extends Foo_Abstract { 
    //Foo must 'implement' $property 
    public $tablename = 'users'; 
} 

回答

121

有沒有這樣的東西定義一個屬性。

您只能聲明屬性,因爲它們是初始化時在內存中保留的數據的容器。

另一方面,函數可以被聲明(類型,名稱,參數)而不被定義(函數體缺失),因此可以被抽象化。

「摘要」只是表示聲明瞭一些內容,但沒有定義,因此在使用它之前,您需要定義它或者它變得毫無用處。

+7

+1:很好解釋。 – hakre

+34

沒有明顯的原因,'抽象'這個詞不能用在* static *屬性上 - 但意思稍有不同。例如,它可能表明一個子類必須爲該屬性提供一個值。 – frodeborli

5

正如你可以通過只是測試你的代碼已經發現:

Fatal error: Properties cannot be declared abstract in ... on line 3

沒有,沒有。不能在PHP中聲明屬性。

但是,你可以實現一個getter/setter函數的抽象,這可能是你在找什麼。

屬性不落實(特別是公共性),他們只是存在(或不):

$foo = new Foo; 
$foo->publicProperty = 'Bar'; 
42

沒有,有沒有辦法強制執行與編譯器,你就必須使用運行時檢查(比如,在構造函數中)爲$tablename變量,如:

class Foo_Abstract { 
    public final function __construct(/*whatever*/) { 
    if(!isset($this->tablename)) 
     throw new LogicException(get_class($this) . ' must have a $tablename'); 
    } 
} 

要強制執行對於Foo_Abstract的所有派生類,您必須使Foo_Abstract的構造函數爲final,從而防止重寫。

你可以聲明一個抽象的getter來代替:

abstract class Foo_Abstract { 
    abstract public function get_tablename(); 
} 

class Foo extends Foo_Abstract { 
    protected $tablename = 'tablename'; 
    public function get_tablename() { 
    return $this->tablename; 
    } 
} 
+0

不錯的功能,我喜歡你如何實現抽象屬性。 –

+4

這將要求您在抽象基類中使構造函數最終。 – hakre

+0

@hakre:我不確定我瞭解你嗎? – connec

19

如上所述,不存在這樣的確切定義。 我,但是,使用這種簡單的解決辦法來迫使子類來定義「抽象」屬性:

abstract class Father 
{ 
    public $name; 
    abstract protected function setName(); // now every child class must declare this 
             // function and thus declare the property 

    public function __construct() 
    { 
    $this->setName(); 
    } 
} 

class Son extends Father 
{ 
    protected function setName() 
    { 
    $this->name = "son"; 
    } 

    function __construct(){ 
    parent::__construct(); 
    } 
} 
+0

就解決方法而言,這是相當優雅的。 –

+0

優雅,但不解決'static'屬性的問題。 – Robbert

+1

我不認爲你可以有私人的抽象方法。 – Zorji

10

根據財產的情況下,如果我想強制在孩子的抽象對象屬性的聲明對象,我喜歡在抽象對象構造函數或setter/getter方法中使用關鍵字爲static的常量。

除此之外,如果重新定義,子對象將覆蓋父對象屬性和方法。 例如,如果在父級中聲明一個屬性爲protected,並且在孩子中重新定義爲public,則生成的屬性是公共的。但是,如果該房產在父母中被宣佈爲private,則該房產將保持private,並且對於該孩子不可用。

http://www.php.net//manual/en/language.oop5.static.php

abstract class AbstractFoo 
{ 
    public $bar; 

    public function __construct() 
    { 
     $this->bar = static::BAR; 
    } 
} 

class Foo extends AbstractFoo 
{ 
    //const BAR = 'foobar'; 
} 

$foo = new Foo; //Fatal Error: Undefined class constant 'BAR' (uncomment const BAR = 'foobar';) 
echo $foo->bar; 
+1

這裏最優雅的解決方案 –

4

我今天問自己同樣的問題,我想補充我的兩分錢。

我們希望abstract屬性的原因是要確保子類定義它們,並在它們沒有的時候拋出異常。在我的具體情況中,我需要一些可以與static盟友合作的東西。

理想我想是這樣的:

abstract class A { 
    abstract protected static $prop; 
} 

class B extends A { 
    protected static $prop = 'B prop'; // $prop defined, B loads successfully 
} 

class C extends A { 
    // throws an exception when loading C for the first time because $prop 
    // is not defined. 
} 

我結束了這個實現

abstract class A 
{ 
    // no $prop definition in A! 

    public static final function getProp() 
    { 
     return static::$prop; 
    } 
} 

class B extends A 
{ 
    protected static $prop = 'B prop'; 
} 

class C extends A 
{ 
} 

正如你所看到的,在A我不定義$prop,我卻用它在static獲得者。因此,下面的代碼工作

B::getProp(); 
// => 'B prop' 

$b = new B(); 
$b->getProp(); 
// => 'B prop' 

C,在另一方面,我不定義$prop,所以我得到異常:

C::getProp(); 
// => Exception! 

$c = new C(); 
$c->getProp(); 
// => Exception! 

我必須調用getProp()方法來獲取異常我無法在課堂上加載它,但至少在我的情況下,它非常接近理想的行爲。

我定義getProp()final避免一些聰明的傢伙(又稱自己在6個月)的誘惑做

class D extends A { 
    public static function getProp() { 
     // really smart 
    } 
} 

D::getProp(); 
// => no exception... 
+0

這是非常巧妙的破解。希望這不需要在未來完成。 – CMCDragonkai

1

如果表名的值將不會在對象的生命週期內發生變化,以下將是一個簡單但安全的實施。

abstract class Foo_Abstract { 
    abstract protected function getTablename(); 

    public function showTableName() 
    { 
     echo 'my table name is '.$this->getTablename(); 
    } 
} 

class Foo extends Foo_Abstract { 
    //Foo must 'implement' getTablename() 
    protected function getTablename() 
    { 
     return 'users'; 
    } 
} 

的關鍵在這裏是指定的字符串值「用戶」和子類實現在getTableName時()直接返回。該函數模仿「只讀」屬性。

這與之前發佈的使用附加變量的解決方案非常相似。我也喜歡Marco的解決方案,儘管它可能會更復雜一點。