PHP抽象属性

时间:2011-10-03 12:28:43

标签: php oop abstract-class

有没有办法在PHP中定义抽象类属性?

abstract class Foo_Abstract {
    abstract public $tablename;
}

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

8 个答案:

答案 0 :(得分:140)

没有定义属性的东西。

您只能声明属性,因为它们是初始化时在内存中保留的数据的容器。

另一方面,函数可以声明(类型,名称,参数)而不被定义(缺少函数体),因此,可以使它成为抽象的。

“抽象”仅表示已声明某些内容但未定义,因此在使用之前,您需要定义它或它变得无用。

答案 1 :(得分:45)

不,没有办法强制执行编译器,你必须对$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;
  }
}

答案 2 :(得分:21)

如上所述,没有这样的确切定义。 但是,我使用这个简单的解决方法来强制子类定义“abstract”属性:

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

答案 3 :(得分:18)

如果我想在子对象中强制声明抽象对象属性,则根据属性的上下文,我喜欢在抽象对象构造函数或setter中使用带有static关键字的常量作为属性/ getter方法。

除此之外,如果重新定义,子对象将覆盖父对象属性和方法。 例如,如果属性在父级中声明为protected并在子级中重新定义为public,则结果属性为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;

答案 4 :(得分:6)

我今天问自己同样的问题,我想补充两分钱。

我们希望-keep class com.google.android.gms.** { *; } -dontwarn com.google.android.gms.** 属性的原因是确保子类定义它们并在它们不这样做时抛出异常。在我的具体案例中,我需要一些可以与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 getter中使用它。因此,以下代码可以正常工作

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(),以避免某些聪明人(也就是我自己在6个月内)想要做的事

final

答案 5 :(得分:5)

您可以通过测试代码找到答案:

  

致命错误:第3行的......中无法将属性声明为抽象

不,没有。不能在PHP中将属性声明为抽象。

但是你可以实现一个getter / setter函数抽象,这可能是你正在寻找的。

未实现属性(尤其是公共属性),它们只存在(或不存在):

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

答案 6 :(得分:4)

对抽象属性的需求可以表明设计问题。虽然许多答案实现了Template method pattern种类并且它有效,但它总是看起来很奇怪。

让我们看一下原来的例子:

abstract class Foo_Abstract {
    abstract public $tablename;
}

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

标记某事abstract是为了表明它是必须拥有的东西。好吧,必备值(在这种情况下)是必需的依赖项,因此它应该在实例化期间传递给构造函数

class Table
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function name(): string
    {
        return $this->name;
    }
}

然后,如果你真的想要一个更具体的命名类,你可以像这样继承:

final class UsersTable extends Table
{
    public function __construct()
    {
        parent::__construct('users');
    }
}

如果您使用DI容器并且必须为不同的对象传递不同的表,这将非常有用。

答案 7 :(得分:1)

PHP 7使制作抽象“属性”变得相当容易。就像上面一样,您将通过创建抽象函数来创建它们,但是使用PHP 7可以定义该函数的返回类型,这在构建任何人都可以扩展的基类时使事情变得容易得多。

<?php

abstract class FooBase {

  abstract public function FooProp(): string;
  abstract public function BarProp(): BarClass;

  public function foo() {
    return $this->FooProp();
  }

  public function bar() {
    return $this->BarProp()->name();
  }

}

class BarClass {

  public function name() {
    return 'Bar!';
  }

}

class FooClass extends FooBase {

  public function FooProp(): string {
    return 'Foo!';
  }

  public function BarProp(): BarClass {
    // This would not work:
    // return 'not working';
    // But this will!
    return new BarClass();
  }

}

$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
相关问题