Herança de Objetos

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.

Nota:

Não é permitido sobrescrever uma propriedade de leitura/gravação com um propriedade somente de leitura ou vice versa.

<?php

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 is great.' . PHP_EOL;
}
}

class
Bar extends Foo
{
public function
printItem($string)
{
echo
'Bar: ' . $string . PHP_EOL;
}
}

$foo = new Foo();
$bar = new Bar();
$foo->printItem('baz'); // Output: 'Foo: baz'
$foo->printPHP(); // Output: 'PHP is great'
$bar->printItem('baz'); // Output: 'Bar: baz'
$bar->printPHP(); // Output: 'PHP is great'

?>

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

// Nenhuma notícia é acionada
?>
add a note add a note

User Contributed Notes 8 notes

up
210
jackdracona at msn dot com
14 years ago
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

?>
up
101
Mohammad Istanbouly
7 years ago
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
}
up
25
strata_ranger at hotmail dot com
14 years ago
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]

?>
up
14
akashwebdev at gmail dot com
9 years ago
The Idea that multiple inheritence is not supported is correct but with tratits this can be reviewed.

for e.g.

<?php
trait  custom
{
     public function
hello()
     {
          echo
"hello";
     }
}

trait
custom2
{
       public function
hello()
       {
            echo
"hello2";
       }
}

class
inheritsCustom
{
        use
custom, custom2
       
{
             
custom2::hello insteadof custom;
        }
}

$obj = new inheritsCustom();
$obj->hello();
?>
up
10
jarrod at squarecrow dot com
15 years ago
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!

?>
up
-2
niemans at pbsolo dot nl
4 years ago
Inheritance works at create time, i.e. using the keyword 'new'. Static properties confused my understanding, so in order tho show the effect of visibility to inherintence I've created a simple demo script along with some set and get magic:

<?php
class A {
private
$a   = 'private';
protected
$b = 'protected';
public
$c    = 'public';
static
$d    = 'static';
public function
__construct()
{
   
$this->e = 'constructed';
}
public function
__set($property, $value)
{
    echo
' set ' . $property . '=' . $value;
   
$this->$property=$value;
}
public function
__get($property)
{
    echo
' get ' . $property;
   
$this->$property = 'dynamic'// invokes __set() !!
   
return $this->$property;
}
}

class
B extends A
{
public function
constructMe()
{
   
$this->e = 'constructed2';
}
}

class
C extends B
{
public function
__construct()
{
   
parent::constructMe();
}
}

echo
" \n";
$a = new A();
$b = new B();
echo
" \n";
echo
' B:c='.$b->c;
echo
" \n";
echo
' B:d=' .$b->d;
echo
" \n";

$c = new C();
echo
" \n";

print_r($a);
print_r($b);
print_r($c);

print_r(A::$d);
print_r(B::$d);
print_r(C::$d);

echo
'A class: ';
$R = new reflectionclass('A');
print_r($R->getdefaultproperties());
print_r($R->getstaticproperties());
echo
'B class: ';
$R = new reflectionclass('B');
print_r($R->getdefaultproperties());
print_r($R->getstaticproperties());

?>

This outputs:

set e=constructed
B:c=public
get d set d=dynamic B:d=dynamic
set e=constructed2
A Object
(
    [a:A:private] => private
    [b:protected] => protected
    [c] => public
    [e] => constructed
)
B Object
(
    [a:A:private] => private
    [b:protected] => protected
    [c] => public
    [d] => dynamic
)
C Object
(
    [a:A:private] => private
    [b:protected] => protected
    [c] => public
    [e] => constructed2
)
staticstaticstaticA class: Array
(
    [d] => static
    [a] => private
    [b] => protected
    [c] => public
)
Array
(
    [d] => static
)
B class: Array
(
    [d] => static
    [b] => protected
    [c] => public
)
Array
(
    [d] => static
)

This shows how private variables ($a) are inherited, how static variables ($d) are inherited (by the class, not by the object) and that changing or adding variables in the parent ($e, $d) are not inherited by the child.
up
-4
Anonymous
5 years ago
PHP7 gives you a warning if you redeclare a function in a child class with different parameters. For example:

class foo {
     function print($text='') {
          print text;
     }
}

class bar extends foo {
      function print($text1='',$text2='') {
           print text1.text2
      }
}

will give a PHP Warning:  Declaration of bar::print($text1 = '', $text2 = '') should be compatible with foo::print($text= '').
up
-4
sibian0218 at gmail dot com
6 years ago
I've noticed one thing concerning inheritance...
When declaring an abstract class with a private method,
which is overridden by a sub-class, private takes precedence over public for child class...
(in the case you're redeclaring a method with a different signature in fact).

Hope this helps
To Top