PHP的抽象属性
有没有什么办法可以在PHP中定义抽象类属性?
abstract class Foo_Abstract { abstract public $tablename; } class Foo extends Foo_Abstract { //Foo must 'implement' $property public $tablename = 'users'; }
没有定义财产这样的事情。
您只能声明属性,因为它们是初始化时在内存中保留的数据的容器。
另一方面,函数可以被声明(types,名称,参数)而不被定义(函数体缺失),因此可以被抽象化。
“摘要”只是表示声明了一些东西,但没有定义,所以在使用之前,需要定义它,否则就变成无用的。
不,没有办法用编译器强制执行,你必须使用$tablename
variables的运行时检查(比如在构造函数中),例如:
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; } }
如上所述,没有这个确切的定义。 但是,我使用这个简单的解决方法来强制子类定义“抽象”属性:
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(); } }
根据属性的上下文,如果我想强制在子对象中声明一个抽象对象属性,我喜欢在抽象对象构造函数或setter / getter方法中使用static
属性的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;
正如你可以通过testing你的代码发现的:
致命错误:无法在第3行中声明属性
不,那里没有。 不能在PHP中声明属性。
不过,你可以实现一个getter / setter函数的抽象,这可能是你在找什么。
属性没有实现(特别是公共属性),它们只是存在(或不):
$foo = new Foo; $foo->publicProperty = 'Bar';
我今天也问过自己同样的问题,我想补充两分钱。
我们想要abstract
属性的原因是为了确保子类定义它们,并在没有的时候抛出exception。 在我的具体情况下,我需要一些可以与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
getter中使用它。 因此,下面的代码工作
B::getProp(); // => 'B prop' $b = new B(); $b->getProp(); // => 'B prop'
另一方面,在C
,我没有定义$prop
,所以我得到exception:
C::getProp(); // => Exception! $c = new C(); $c->getProp(); // => Exception!
我必须调用getProp()
方法来获取exception,我不能在类加载,但它是非常接近所需的行为,至less在我的情况。
我将getProp()
定义为final
以避免某个聪明的人 (也就是6个月以来)试图做的事情
class D extends A { public static function getProp() { // really smart } } D::getProp(); // => no exception...
如果tablename的值在对象的生命期内永远不会改变,那么下面将是一个简单而安全的实现。
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'; } }
这里的关键是string值'users'是在子类实现中的getTablename()中直接指定和返回的。 该函数模仿“只读”属性。
这与之前发布的使用附加variables的解决scheme非常相似。 我也喜欢Marco的解决scheme,虽然可能会更复杂一些。