[sid]
Новичок
PHP и множественное наследование
PHP не поддерживает множественное наследование, однако средства overloading, которые присутствуют в PHP5 позволяют реализовать ее некоторое подобие.
Уверен, что знающие люди уже поняли суть работы.
Как можно использовать подобный класс для реализации множественного наследования?
Здесь класс foo наследуется от классов A и B.
Давайте проверим.
Вобщем получается следующая картина.
Плюсы:
Итог... Вряд ли это можно назвать реализацией множественного наследования, скорее это прокси объект к нескольком классам. Но внекоторых случаях позволяет сэмулировать функциональность множественного наследования
PHP не поддерживает множественное наследование, однако средства overloading, которые присутствуют в PHP5 позволяют реализовать ее некоторое подобие.
PHP:
class multipleInheritance
{
private $classes = array();
protected function __construct()
{
if ( func_num_args() < 2 )
{
throw new Exception("Invalid arguments count. Must be 2 or more");
}
$classes = func_get_args();
foreach ( $classes as $class )
{
if ( !is_string($class) || strlen($class) <= 0 )
{
throw new Exception("Invalid class name");
}elseif ( !class_exists($class) )
{
throw new Exception("Class '{$class}' did not exsit");
}elseif ( isset($this->classes[$class]) )
{
throw new Exception("Class '{$class}' must be refered only once in class declaration");
}
$this->classes[$class] = new $class;
}
}
public function __get($key)
{
$objects = $this->getObjectsHaveProperty($key);
$objectsCnt = count($objects);
if ( $objectsCnt <= 0 )
{
throw new Exception("Invalid property '{$key}'.");
}elseif ( $objectsCnt > 1 )
{
throw new Exception("Property '{$key}' have more than one class.");
}
return $objects[0]->$key;
}
public function __set($key, $value)
{
$objects = $this->getObjectsHaveProperty($key);
$objectsCnt = count($objects);
if ( $objectsCnt <= 0 )
{
return $this->$key = $value;
}elseif ( $objectsCnt > 1 )
{
throw new Exception("Property '{$key}' have more than one class.");
}
return $objects[0]->$key = $value;
}
// Прокси метод, редиректор... называйте как хотите :)
public function __call($string, $args)
{
$objects = $this->getObjectsImplementsMethod($string);
$objectsCnt = count($objects);
if ( $objectsCnt <= 0 )
{
throw new Exception("Method '{$string}' not implemented");
}elseif ( $objectsCnt > 1 )
{
$classNames = array();
foreach ( $objects as $object )
{
$classNames[] = get_class($object);
}
$object = implode(', ', $classNames);
throw new Exception("Method '{$string}' implemented by classes {$object}. You must overload this method in child class");
}else{
$callAddress = array($objects[0], $string);
$arguments = $args;
return call_user_func_array($callAddress, $arguments);
}
}
// Возвращает массив объектов, которые реализуют метод $methodName
protected function getObjectsImplementsMethod($methodName)
{
$ret = array();
foreach ( $this->classes as $class )
{
if ( method_exists($class, $methodName) )
{
$ret[] = $class;
}
}
return $ret;
}
// Возвращает массив объектов, которые обладают свойством $propName
protected function getObjectsHaveProperty($propName)
{
$ret = array();
foreach ( $this->classes as $class )
{
$properties = get_object_vars($class);
if ( in_array($propName, array_keys($properties)) )
{
$ret[] = $class;
}
}
return $ret;
}
}
Как можно использовать подобный класс для реализации множественного наследования?
PHP:
class A
{
public $a = 'foo A';
public function testA()
{
return 'Hi this is '.__METHOD__;
}
public function foo()
{
return 0;
}
}
class B
{
public $b = 'foo B';
public function testB()
{
return 'Hi this is '.__METHOD__;
}
public function foo()
{
return 0;
}
}
// Этот класс наследуется от классов A и B
class foo extends multipleInheritance
{
public $u = 'asd';
function __construct()
{
multipleInheritance::__construct('A', 'B');
}
}
Давайте проверим.
PHP:
try
{
$object = new foo();
$ret = $object->testA(); // Вызывается A::testA()
echo "A::testA returned '{$ret}'\n";
$ret = $object->testB(); // Вызывается B::testB()
echo "B::testB returned '{$ret}'\n";
echo "A::a is '{$object->a}'\n"; // Выводится A::a
echo "B::b is '{$object->b}'\n"; // Выводится B::b
echo "A::a is '".($object->a = 'bar A')."'\n"; // Меняется A::a
echo "B::b is '".($object->b = 'bar B')."'\n"; // Меняется B::b
$object->foo(); // Генерируется ошибка, так как метод foo
// определен в двух классах
} catch ( Exception $e )
{
echo "Sorry, failed because of ".$e->getMessage();
}
Плюсы:
- Можно прозрачно вызывать методы двух родительских классов
- Можно получать доступ к свойствам родительских классов
- Можно использовать оператор :: для вызова метода конкретного родительского класса
- Использования оператора :: может привести к непредсказуемым последствиям, так как методу передается контекст дочернего объекта который фактически наследуется от multipleInheritance, а не от A и B
- При использовании оператора -> метод вызываеться в контексте своего класса (родительского, а не дочернего), со всеми вытекающими. То есть вы не сможете вызвать из родительского класса метод дочернего
Итог... Вряд ли это можно назвать реализацией множественного наследования, скорее это прокси объект к нескольком классам. Но внекоторых случаях позволяет сэмулировать функциональность множественного наследования