Respuestas:
No existe tal cosa como definir una propiedad.
Solo puede declarar propiedades porque son contenedores de datos reservados en la memoria en la inicialización.
Por otro lado, una función puede declararse (tipos, nombre, parámetros) sin definirse (falta el cuerpo de la función) y, por lo tanto, puede hacerse abstracta.
"Resumen" solo indica que algo se declaró pero no se definió y, por lo tanto, antes de usarlo, debe definirlo o se volverá inútil.
No, no hay forma de aplicar eso con el compilador, tendría que usar verificaciones en tiempo de ejecución (por ejemplo, en el constructor) para la $tablename
variable, por ejemplo:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
Para hacer cumplir esto para todas las clases derivadas de Foo_Abstract, tendría que hacer el constructor de Foo_Abstract final
, evitando la anulación.
En su lugar, podría declarar un captador abstracto:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Dependiendo del contexto de la propiedad si quiero forzar la declaración de una propiedad de objeto abstracto en un objeto hijo, me gusta usar una constante con la static
palabra clave para la propiedad en el constructor de objetos abstractos o métodos setter / getter. Opcionalmente, puede usar final
para evitar que el método se anule en clases extendidas.
Aparte de eso, el objeto secundario anula la propiedad y los métodos del objeto principal si se redefine. Por ejemplo, si una propiedad se declara como protected
en el padre y se redefine como public
en el hijo, la propiedad resultante es pública. Sin embargo, si la propiedad se declara private
en el padre, permanecerá private
y no estará disponible para el niño.
http://www.php.net//manual/en/language.oop5.static.php
abstract class AbstractFoo
{
public $bar;
final 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;
Como se indicó anteriormente, no existe tal definición exacta. Sin embargo, utilizo esta solución simple para forzar a la clase secundaria a definir la propiedad "abstracta":
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();
}
}
static
propiedades.
the only "safe" methods to have in a constructor are private and/or final ones
, ¿no es mi solución este caso? estoy usando
$name
. Puede implementar la setName()
función sin que realmente se configure $name
.
getName
lugar de $name
funciona mejor. abstract class Father { abstract protected function getName(); public function foo(){ echo $this->getName();} }
Hoy me hice la misma pregunta y me gustaría agregar mis dos centavos.
La razón por la que nos gustaría tener abstract
propiedades es para asegurarnos de que las subclases las definan y arrojen excepciones cuando no lo hacen. En mi caso específico, necesitaba algo que pudiera funcionar con static
aliado.
Idealmente me gustaría algo como esto:
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.
}
Terminé con esta implementación
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
{
}
Como puede ver, en A
No lo defino $prop
, pero lo uso en un static
captador. Por lo tanto, el siguiente código funciona
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
En C
, por otro lado, no defino $prop
, por lo que obtengo excepciones:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
Debo llamar al getProp()
método para obtener la excepción y no puedo obtenerlo al cargar la clase, pero está bastante cerca del comportamiento deseado, al menos en mi caso.
Defino getProp()
como final
evitar que algún tipo inteligente (también conocido como yo en 6 meses) tenga la tentación de hacer
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
Como podría haber descubierto simplemente probando su código:
Error grave: las propiedades no se pueden declarar abstractas en ... en la línea 3
No no hay. Las propiedades no pueden declararse abstractas en PHP.
Sin embargo, puede implementar un resumen de la función getter / setter, esto podría ser lo que está buscando.
Las propiedades no se implementan (especialmente las propiedades públicas), solo existen (o no):
$foo = new Foo;
$foo->publicProperty = 'Bar';
La necesidad de propiedades abstractas puede indicar problemas de diseño. Si bien muchas de las respuestas implementan un tipo de patrón de método de Plantilla y funciona, siempre parece un poco extraño.
Echemos un vistazo al ejemplo original:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
Marcar algo abstract
es indicarlo como algo imprescindible. Bueno, un valor imprescindible (en este caso) es una dependencia requerida, por lo que debe pasarse al constructor durante la creación de instancias :
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Entonces, si realmente desea una clase con nombre más concreta, puede heredar así:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
Esto puede ser útil si usa el contenedor DI y tiene que pasar diferentes tablas para diferentes objetos.
PHP 7 lo hace bastante más fácil para hacer "propiedades" abstractas. Al igual que anteriormente, los creará creando funciones abstractas, pero con PHP 7 puede definir el tipo de retorno para esa función, lo que facilita mucho las cosas cuando construye una clase base que cualquiera puede ampliar.
<?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;
si el valor del nombre de la tabla nunca cambiará durante la vida útil del objeto, la siguiente será una implementación simple pero segura.
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';
}
}
La clave aquí es que el valor de cadena 'usuarios' se especifica y se devuelve directamente en getTablename () en la implementación de la clase secundaria. La función imita una propiedad de "solo lectura".
Esto es bastante similar a una solución publicada anteriormente que utiliza una variable adicional. También me gusta la solución de Marco, aunque puede ser un poco más complicada.