Наследование
Наследование — это хорошо зарекомендовавший себя принцип программирования. PHP использует этот принцип в своей объектной модели. Этот принцип будет распространяться на то, каким образом множество классов и объектов относятся друг к другу.
Например, когда вы расширяете класс, дочерний класс наследует все публичные и защищенные методы из родительского класса. До тех пор пока не будут эти методы переопределены, они будут сохранять свою исходную функциональность.
Это полезно для определения и абстрагирования функциональности и позволяет реализовать дополнительную функциональность в похожих объектах без необходимости реализовывать всю общую функциональность.
Замечание:
Пока не используется автозагрузка, классы должны быть объявлены до того, как их будут использовать. Если класс расширяет другой, то родительский класс должен быть объявлен до наследующего класса. Это правило применяется к классам, которые наследуют другие классы или интерфейсы.
Пример #1 Пример наследования
<?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'
?>
- Введение
- Основы
- Свойства
- Константы классов
- Автоматическая загрузка классов
- Конструкторы и деструкторы
- Область видимости
- Наследование
- Оператор разрешения области видимости (::)
- Ключевое слово "static"
- Абстрактные классы
- Интерфейсы объектов
- Трейты
- Anonymous classes
- Перегрузка
- Итераторы объектов
- Магические методы
- Ключевое слово "final"
- Клонирование объектов
- Сравнение объектов
- Контроль типа
- Позднее статическое связывание
- Объекты и ссылки
- Сериализация объектов
- Журнал изменений ООП
Коментарии
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!
?>
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 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]
?>
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();
?>
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
}
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
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= '').
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.