All pastes #928739 Raw Edit

ewgra

public text v1 · immutable
#928739 ·published 2008-03-05 07:46 UTC
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 );

?>