Siguiendo con el tema de la Herencia voy a hablar un poco de como podemos controlar lo que heredamos, si nos fijamos en los ejemplos anteriores siempre marque los atributos y los métodos como públicos (public), pero esto no tiene porque ser así, si queremos podemos cambiar su grado de visibilidad, hagamos una prueba cambiando un método a privado:

ClasePadre.php:

<?php 
class ClasePadre { 
    public $atributo = 'Atributo Padre'; 
    public function __construct(){ 
        echo __CLASS__; 
    } 

    //Método privado 
    private function miMetodo(){ 
        echo "Método Padre"; 
    } 
} 
?>

ClaseHija.php:

<?php 
require_once('ClasePadre.php'); 
class ClaseHija extends ClasePadre { 
    //Lamamos de forma interna al método miMetodo como si fuera de esta clase. 
    public function llamarMetodo(){ 
        $this->miMetodo(); 
    } 
} 
?>

script.php:

<?php 
require_once('ClaseHija.php'); 
$obj = new ClaseHija(); //Imprime: Clase Padre 
echo $obj->atributo; //Imprime: Atributo Padre 
$obj->llamarMetodo(); //Imprime error: Fatal error: Call to private method ClasePadre::miMetodo() from context 'ClaseHija' 
?>

He intentado llamar de forma interna al método de la clase “padremiMetodo() pero este al ser privado nos ha devuelto un error, como te imaginarás al marcar como privado un método o atributo no permite ni tan siquiera ser usado por una clase “hija”. ¿La solución es marcarlos como públicos?, no. Como ya explique en tema de “entendiendo la visibilidad” existe otro nivel de protección llamado protected, este nivel se puede decir que es similar a declarar como privado un atributo puesto que bloquea el acceso desde fuera de la clase, pero ahora si que nos permite que las clases “hijas” puedan acceder y manipular el atributo o método en cuestión, hagamos una prueba modificando la clase “padre”:

ClasePadre.php:

<?php 
class ClasePadre { 
    public $atributo = 'Atributo Padre'; 
    public function __construct(){ 
        echo __CLASS__; 
    } 

    //Método Protegido protected function miMetodo(){ 
        echo "Método Padre"; 
    } 
} 
?>

script.php:

<?php 
require_once('ClaseHija.php'); 
$obj = new ClaseHija(); //Imprime: Clase Padre 
echo $obj->atributo; //Imprime: Atributo Padre 
$obj->llamarMetodo(); //Imprime: Método Padre 
$obj->miMetodo(); //Imprime error: Fatal error: Call to protected method ClasePadre::miMetodo() from context '' 
?>

Ahora hemos realizado dos llamadas, una interna a través del método de la clase “hijallamarMetodo() y una de forma externa. La llamada interna nos ha devuelto el resultado esperado que no es más que la impresión en pantalla de “Método Padre”, pero la llamada externa nos devuelve un error de acceso. Esto quiere decir que el nivel protected nos ha permitido heredar el método para acceder internamente desde la clase “hija” pero no de forma publica.

Hay que tener en cuenta que los niveles nunca pueden ser más restrictivos en la clase “hija” que en la clase “padre”, esto significa que si un método en la clase “padre” es publico en la hija deberá serlo, pero si en la padre es private o protected, en la hija podrá ser publico.

Podría darse el caso de que al diseñar una clase no quisiéramos que se pudiera heredar, para evitar la herencia provocando un error al intentarlo solo tenemos que añadir en la declaración de la clase el operador final:

ClasePadre.php:

<?php 
final class ClasePadre { 
    public $atributo = 'Atributo Padre'; 
    public function __construct(){ 
        echo __CLASS__; 
    } 

    //Método Protegido
    protected function miMetodo(){ 
        echo "Método Padre"; 
    } 
} 
?>

Esto genera un error tipo “Fatal error: Class ClaseHija may not inherit from final class (ClasePadre)” debido a que hemos bloqueado la herencia para ClasePadre. Si lo que queremos es simplemente evitar que se sobrescriba un método, para así asegurarnos de que siempre se ejecutara tal y como se ha definido en la clase “padre” lo que debemos de hacer es añadir el operador final en su declaración:

ClasePadre.php:

<?php 
class ClasePadre { 
    public $atributo = 'Atributo Padre'; 
    public function __construct(){ 
        echo __CLASS__; 
    } 

    //Método imposible de sobrescribir 
    public final function miMetodo(){ 
        echo "Método Padre"; 
    } 
} 
?>

Por lo general el operador final no se suele usar, salvo raras excepciones dado que la potencia de los objetos reside en la posibilidad de heredar y extender las funcionalidades de las clases.