Herança é um conceito de programação estabelecido, e o PHP faz
use deste em seu modelo de objetos. Este princípio afeta a forma
com que classes e objetos se relacionam com outras.
Por exemplo, ao estender uma classe, a subclasse herda todos os métodos
públicos e protegidos, propriedades e constantes da classe pai.
A não que uma classe sobrescreva
estes métodos, eles manterão sua funcionalidade original.
Isto é útil para definir uma funcionalidade abstrata, e permitir a
implementação de uma funcionalidade adicional em objetos similares sem a
necessidade de reimplementar todas as funcionalidades compartilhadas.
Os métodos privados de uma classe pai não são acessíveis a uma classe filha. Como resultado,
as classes filhas podem reimplementar um método privado sem levar em conta as regras normais
de herança. Antes do PHP 8.0.0, entretanto, as restrições final e static
eram aplicadas aos métodos privados. Desde o PHP 8.0.0, a única restrição de método privado
que é aplicada é private final para construtores, já que essa
é uma maneira comum de "desabilitar" o construtor ao usar métodos de fábricação estáticos.
A visibilidade
de métodos, propriedades e constantes pode ser relaxada, por exemplo, um
método com protected pode ser marcado como
public, mas não pode ser restrito, por exemplo,
marcar uma propriedade que tenha public como private.
Uma exceção são os construtores, cuja visibilidade pode ser restrita, ou seja,
um construtor public pode ser declarado como private
numa classe filha.
Nota:
A não ser que o autoload seja usado, as classes devem ser definidas antes de
utilizadas. Se uma classe estende outra, a classe pai deve ser declarada
antes da estrutura da classe filha. Esta regra se aplica a classes que herdam
outras classes e interfaces.
class A { public int $prop; } class B extends A { // Illegal: read-write -> readonly public readonly int $prop; } ?>
Exemplo #1 Exemplo de Herança
<?php
class Foo { public function printItem($string) { echo 'Foo: ' . $string . PHP_EOL; }
public function printPHP() { echo 'PHP é ótimo' . PHP_EOL; } }
class Bar extends Foo { public function printItem($string) { echo 'Bar: ' . $string . PHP_EOL; } }
$foo = new Foo(); $bar = new Bar(); $foo->printItem('baz'); // Saída: 'Foo: baz' $foo->printPHP(); // Saída: 'PHP é ótimo' $bar->printItem('baz'); // Saída: 'Bar: baz' $bar->printPHP(); // Saída: 'PHP é ótimo'
?>
Compatibilidade de Tipo de Retorno com Classes Internas ¶
Antes do PHP 8.1, a maioria das classes ou métodos internos não declaravam seus tipos de retorno,
e qualquer tipo de retorno era permitido ao estendê-los.
A partir do PHP 8.1.0, a maioria dos métodos internos começaram a declarar seu tipo de retorno de forma "experimental",
nesse caso o tipo de retorno dos métodos deve ser compatível com o pai sendo estendido,
do contrário, um aviso de descontinuação é emitido.
Note que a ausência de uma declaração de retorno explícita também é considerada uma incompatibilidade de assinatura
e, portanto, resulta no aviso de descontinuação.
Se o tipo de retorno não puder ser declarado para um método que sobrepõe devido à preocupações com compatibilidade entre versões PHP,
um atributo ReturnTypeWillChange pode ser adicionado para silenciar o aviso de descontinuação.
Exemplo #2 O método que sobrepõe não declara nenhum tipo de retorno
<?php class MeuDateTime extends DateTime { public function modify(string $modifier) { return false; } }
// "Deprecated: Return type of MeuDateTime::modify(string $modifier) should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" a partir do PHP 8.1.0 ?>
Exemplo #3 O método que sobrepõe declara um tipo de retorno errado
<?php class MeuDateTime extends DateTime { public function modify(string $modifier): ?DateTime { return null; } }
// "Deprecated: Return type of MeuDateTime::modify(string $modifier): ?DateTime should either be compatible with DateTime::modify(string $modifier): DateTime|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice" a partir do PHP 8.1.0 ?>
Exemplo #4 O método que sobrepõe declara um tipo de retorno errado sem um aviso de descontinuação
<?php class MeuDateTime extends DateTime { /** * @return DateTime|false */ #[\ReturnTypeWillChange] public function modify(string $modifier) { return false; } }
Here is some clarification about PHP inheritance – there is a lot of bad information on the net. PHP does support Multi-level inheritance. (I tested it using version 5.2.9). It does not support multiple inheritance.
This means that you cannot have one class extend 2 other classes (see the extends keyword). However, you can have one class extend another, which extends another, and so on.
Example:
<?php class A { // more code here }
class B extends A { // more code here }
class C extends B { // more code here }
$someObj = new A(); // no problems $someOtherObj = new B(); // no problems $lastObj = new C(); // still no problems
I think the best way for beginners to understand inheritance is through a real example so here is a simple example I can gave to you
<?php
class Person { public $name; protected $age; private $phone;
public function talk(){ //Do stuff here }
protected function walk(){ //Do stuff here }
private function swim(){ //Do stuff here } }
class Tom extends Person { /*Since Tom class extends Person class this means that class Tom is a child class and class person is the parent class and child class will inherit all public and protected members(properties and methods) from the parent class*/
/*So class Tom will have these properties and methods*/
//public $name; //protected $age; //public function talk(){} //protected function walk(){}
//but it will not inherit the private members //this is all what Object inheritance means }
You can force a class to be strictly an inheritable class by using the "abstract" keyword. When you define a class with abstract, any attempt to instantiate a separate instance of it will result in a fatal error. This is useful for situations like a base class where it would be inherited by multiple child classes yet you want to restrict the ability to instantiate it by itself.
Example........
<?php
abstract class Cheese { //can ONLY be inherited by another class }
class Cheddar extends Cheese { }
$dinner = new Cheese; //fatal error $lunch = new Cheddar; //works!
I was recently extending a PEAR class when I encountered a situation where I wanted to call a constructor two levels up the class hierarchy, ignoring the immediate parent. In such a case, you need to explicitly reference the class name using the :: operator.
Fortunately, just like using the 'parent' keyword PHP correctly recognizes that you are calling the function from a protected context inside the object's class hierarchy.
E.g:
<?php class foo { public function something() { echo __CLASS__; // foo var_dump($this); } }
class foo_bar extends foo { public function something() { echo __CLASS__; // foo_bar var_dump($this); } }
class foo_bar_baz extends foo_bar { public function something() { echo __CLASS__; // foo_bar_baz var_dump($this); }
public function call() { echo self::something(); // self echo parent::something(); // parent echo foo::something(); // grandparent } }
error_reporting(-1);
$obj = new foo_bar_baz(); $obj->call();
// Output similar to: // foo_bar_baz // object(foo_bar_baz)[1] // foo_bar // object(foo_bar_baz)[1] // foo // object(foo_bar_baz)[1]