rendered paste body<?php
/**
* Класс, реализующий множественное наследование в PHP
* в эксплуатацию не введен, набросок
* @todo Обработка через Reflection видимостей переменных и методов (private, static и т.п.) в __call, __get, __set
*/
class MultipleExtendPattern
{
/**
* Экземпляры унаследованных классов
* @var mixed
*/
private $ExtendsClasses = array();
public function __construct( /** $Class1, ..., $Class2 = array( 'ClassName', 'ConstructorArguments' => array( 'Param1', ..., 'ParamN' ) ), ... */ )
{
# Создаем экзепляры наследуемых классов
foreach( func_get_args() as $Class )
{
$ClassName = '';
$ConstructorArguments = array();
if( is_array( $Class ) )
{
$ClassName = array_shift( $Class );
$ConstructorArguments = array_shift( $Class );
}
else $ClassName = $Class;
# Через Reflection создаем экземпляр
$Reflection = new ReflectionClass( $ClassName );
$this->ExtendsClasses[] = call_user_method_array( 'newInstance', $Reflection, &$ConstructorArguments );
}
}
/**
* Перехватываем вызовы методов
* @param string $Method
* @param array $Arguments
* @return mixed
* @todo необходимо ввести правила, определяющие действия при ситуации, когда вызываемый метод находиться в двух и более наследуемых объектах
*/
private function __call( $Method, $Arguments )
{
# Проходимся по всем классам, узнавая у кого есть вызываемый метод
foreach( $this->ExtendsClasses as $Object )
{
if( method_exists( $Object, $Method ) )
{
# Делаем вызов метода
return call_user_method_array( $Method, $Object, &$Arguments );
}
}
}
/**
* Перехватываем обращение к переменным класса
* @param string $VariableName
*/
private function __get( $VariableName )
{
# Проходимся по всем классам, узнавая у кого есть вызываемая переменная
foreach( $this->ExtendsClasses as $Object )
{
if( property_exists( $Object, $VariableName ) )
{
return $Object->{$VariableName};
}
}
}
/**
* Прямое обращение к классам
* @param string $ClassName
* @return mixed
*/
public function getObject( $ClassName )
{
foreach( $this->ExtendsClasses as $Object )
{
if( get_class( $Object ) == $ClassName )
{
return $Object;
}
}
}
}
/**
* Потестируем немного
*/
Class A
{
public $AClassProperty = 'AClassProperty';
static $String;
function __construct( $String = '' )
{
self::$String = $String;
$String = 'AConstructByReference' . PHP_EOL;
}
function AFunction( $String = null )
{
if( is_null( $String ) ) $String = self::$String;
echo 'AFunction: ' . $String . PHP_EOL;
}
}
Class B
{
function BFunction( $String )
{
echo 'BFunction: ' . $String . PHP_EOL;
$String = 'BFunction: BFunctionByReference';
}
}
$AString = 'StringA';
$BString = 'StringB';
$FirstClass = array( 'A', 'constructor_arguments' => array( &$AString ) );
$MultipleExtend = new MultipleExtendPattern( $FirstClass, 'B' );
echo PHP_EOL . 'Methods test: ' . PHP_EOL;
$MultipleExtend->AFunction();
$MultipleExtend->AFunction( 'AString' );
$MultipleExtend->BFunction( &$BString );
echo PHP_EOL . 'By reference test: ' . PHP_EOL;
echo $AString;
echo $BString;
echo PHP_EOL . PHP_EOL . 'Properties test: ' . PHP_EOL;
echo $MultipleExtend->AClassProperty;
echo PHP_EOL . PHP_EOL . 'ByClassTest: ' . PHP_EOL;
echo $MultipleExtend->getObject( 'A' )->AClassProperty . PHP_EOL;
echo $MultipleExtend->getObject( 'B' )->BFunction( $BString );
?>