Piszę już od jakiegoś czasu framework pod grę przeglądarkową. Gierka ma być ogólnodostępna i mieć proste api pod programowanie modyfikacji ale nie o tym. Ostatecznie kod ma być dostępny dla wszystkich tj. ktoś chce sobie pograć wchodzi na stronę pobiera grę (ew. modyfikacje) i uruchamia na localhoście lub na swoim serwerze. Nie martwię się zbytnio optymalizację gdyż gra nie zakłada istnienia potężnego serwera dla kilku tysięcy graczy - klepię ją po godzinach i dla zdobycia umiejętności w php, js, css itd. Chciałbym w tym wątku zadawać pytania odnośnie samego frameworka roboczo nazwanego Azure.

Z założenia składa się on z trzech różnych typów modułów:

  • Komponenty - które można śmiało wykorzystać także w innych aplikacjach np. konfiguracja, dla wyróżnienia posiadają przed swoimi nazwami C,
  • Moduły bazowe - stanowią integralną część frameworka np. główna klasa aplikacji, initializer (coś jak bootstrap zend) itd. przed nazwą posiadają B,
  • Narzędzia - proste moduły pozwalające na operowaniu danymi np. kontenery, stosy, validatory, filtry itd. literka U

I tak to zaprojektowałem, że każdy komponent dziedziczy ze wspólnej klasy abstrakcyjnej a wygląda ona tak:

namespace Azure\CBase\Abstracts
{
	
    if (!defined('AZURE')) exit('No direct script access allowed');

    use Azure\CBase\Exceptions\CInvalidArgumentException;
	
    /*
     * The base class for each component AzureFramework (class starts 
     * with the letter "C") shorting methods for basic operations on 
     * the component and its automatic configuration.
     * 
     * Most contained in the base class methods and fields component has the
     * prefix "c". In addition, the method can not be overridden because they 
     * are final, exception is the method of "__initialize". 
     * 
     * Classes that inherit from the base class component to work properly on 
     * an automatic configuration mechanism requires a protected field called 
     * an "cAccessorPrefixes" containing an array with the names of prefixes
     * methods mutators.
     * 
     * @package Azure\CBase
     * @subpackage Abstracts
     */
    class CBaseAbstract
    {
        /*
         * It contains an associative array through which the component is 
         * automatically configured, for example, if the array is an element 
         * called "base" and the "example" component will try to find the field
         *  in the component class called "base" and assign it 
         * a value of "example".
         * 
         * @access protected
         * @var array
         */
        protected $cConfiguration = array();
        
        /*
         * Contains an object of reflection class, required for proper operation 
         * of the class.
         * 
         * @access protected
         * @var \ReflectionClass|null
         */
        protected $cReflection = null;
        
        /*
         * It contains an array with the names of properties defined 
         * in the class.
         * 
         * @access protected
         * @var array
         */
        protected $cProperties = array();
        
        /*
         * It contains an array with the names of methods defined 
         * in the class. 
         * 
         * @access protected
         * @var array
         */
        protected $cMethods = array();
        
        /*
         * It includes an array of items that have not been used for automatic 
         * configuration object. Sometimes they are used to configure other
         * objects contained in another object.
         * 
         * @access protected
         * @var array
         */
        protected $cOptions = array();
        
        /*
         * Contains arguments that were passed to the constructor of the class 
         * beyond the configuration of object.
         * 
         * @access protected
         * @var array
         */
        protected $cArguments = array();
        
        /*
         * The default constructor argument using the component configuration to 
         * automatically configure the object.
         * 
         * @access public
         * @param array $configuration
         * @return void
         */
        public function __construct($configuration = array())
        {
            $arguments = func_get_args();
            unset($arguments[0]);
            
            $arguments = array_values($arguments);
            
            if (count($arguments) > 0) {
                $this->cArguments = $arguments;
            }
            
            $this->cPrepare();
            $this->cAutoConfigure($configuration);
            $this->cInitialize();
        }
        
        /*
         * Method of preparing an object for action, creates a reflection class 
         * and sets the basic values ​​of certain fields.
         * 
         * @access protected
         * @return void
         */
        final protected function cPrepare()
        {
            $reflection = new \ReflectionClass($this);
            
            $this->cReflection = $reflection;
            
            $properties = $reflection->getProperties();
            $methods = $reflection->getMethods();
            
            foreach ($properties as $property) {
                array_push($this->cProperties, $property->getName());
            }
            
            foreach ($methods as $method) {
                array_push($this->cMethods, $method->getName());
            }
        }
        
        /*
         * The basic method of the component responsible for the configuration 
         * based on the array passed to the constructor.
         * 
         * @access protected
         * @param array $configuration
         * @throws Azure\CBase\Exceptions\CInvalidArgumentException If provided 
         * argument is not a type of 'array'.
         * @return void
         */
        final protected function cAutoConfigure($configuration)
        {
            if (is_array($configuration)) {
                $config = $configuration;
            } else {
                throw new CInvalidArgumentException('Component configuration must be array or ' . 
                	'object instance of Azure\\CConfiguration\\Interfaces\\CConfiguration.');
            }
            
            $this->cConfiguration = $config;
            
            foreach ($config as $name => $value) {
                $propertyName = lcfirst($name);
                
                if (in_array($propertyName, $this->cProperties)) {
                    $method = $this->cSearchPropertyMethod($name);

                    if ($method !== false) {
                        $this->$method($value);
                    } else {
                        $this->cSetOption($name, $value);
                    }
                } else {
                    $this->cSetOption($name, $value);
                }
            }
        }
        
        /*
         * The method looks for the method name using the fields contained in 
         * the class 'cAccessorPrefixes'.
         * 
         * @access protected
         * @param string $name
         * @return false|string
         */
        final protected function cSearchPropertyMethod($name)
        {
            if (in_array('cAccessorPrefixes', $this->cProperties)) {
                $prefixes = $this->cAccessorPrefixes;
            } else {
                $prefixes = array();
            }
            
            foreach ($prefixes as $prefix) {
                $methodName = $prefix . ucfirst($name);

                if (in_array($methodName, $this->cMethods)) {
                    return $methodName;
                }
            }
            
            return false;
        }
        
        /*
         * Sets the value of the option object is not used during the automatic 
         * configuration.
         * 
         * @access protected
         * @param string $name
         * @param mixed $value
         * @return void
         */
        final protected function cSetOption($name, $value)
        {
            $this->cOptions[$name] = $value;
        }
        
        /*
         * Gets the option to object if it does not exist returns false.
         * 
         * @access protected
         * @param string $name 
         * @return mixed If option doesn`t exists return false.
         */
        final protected function cGetOption($name)
        {
            if ($this->cHasOption($name)) {
                return $this->cOptions[$name];
            }
            
            return false;
        }
        
        /*
         * The method checks whether the option with the given name exists in 
         * the component and returns a boolean value of this operation.
         * 
         * @access protected
         * @param string $name
         * @return boolean
         */
        final protected function cHasOption($name)
        {
            if (array_key_exists($name, $this->cOptions)) {
                return true;
            }
            
            return false;
        }
        
        /*
         * The method removes the option of the given name of the object if 
         * it exists.
         * 
         * @access protected
         * @param string $name
         * @return void
         */
        final protected function cDeleteOption($name)
        {
            if ($this->cHasOption($name)) {
                unset($this->cOptions[$name]);
            }
        }
        
        /*
         * When an object is not required to perform an operation before the 
         * constructor (which in the case of a component is actually executed 
         * in the __ initialize). This method spradza whether there is a method 
         * __ before the class, if it starts it, then proceed just as in the 
         * case of the initialize method __ and __ after.
         * 
         * @access protected
         * @return void
         */
        final protected function cInitialize()
        {
            if (in_array('__before', $this->cMethods)) {
                $this->__before($this->cArguments);
            }
            
            if (in_array('__initialize', $this->cMethods)) {
                $this->__initialize($this->cArguments);
            }
            
            if (in_array('__after', $this->cMethods)) {
                $this->__after($this->cArguments);
            }
        }
        
        /*
         * Constructors in components do not work in the normal way. Similar 
         * action to the default constructor (__construct) has a method 
         * __initialize. The argument is passed the array of successive 
         * arguments forwarded her at the time of object creation (excluding the 
         * configuration of an object).
         * 
         * @access protected
         * @param array $arguments
         * @return void
         */
        protected function __initialize($arguments)
        {
            
        }
    }
	
} 

Dzięki dziedziczeniu z tej klasy każdy komponent może być konfigurowany przy jego utworzeniu.

class SimpleComponent extends Azure\CBase\Abstracts\CBaseAbstract
{
    protected $name;
	protected $surname;
	protected $age;
	
	public function setName($name)
	{
		$this->name = (string) $name;
	}
	
	public function setSurname($surname)
	{
		$this->surname = (string) $surname;
	}
	
	public function setAge($age)
	{
		$this->age = (int) $age;
	}
}

Tak wygląda przykładowa klasa komponentu. I teraz:

$c = new SimpleComponent(array('age' => 26, 'name' => 'Jan', 'surname' => 'kowalski'));

Sprawi, że odpowiednie pola zostaną uzupełnione wartościami z tablicy przekazanej do konstruktora. Może się zdarzyć tak, że do konstruktora będziemy potrzebowali przekazać pewną inną wartość, możemy wtedy nadpisać konstruktor:

class SimpleComponent extends Azure\CBase\Abstracts\CBaseAbstract
{
        protected $name;
	protected $surname;
	protected $age;
	
        public function __construct($adress, $options = array())
        {
                parent::__construct($options, $adress);
        }

	public function setName($name)
	{
		$this->name = (string) $name;
	}
	
	public function setSurname($surname)
	{
		$this->surname = (string) $surname;
	}
	
	public function setAge($age)
	{
		$this->age = (int) $age;
	}
}

W takim wypadku obsługę zmiennej $adress możemy napisać w chronionej metodzie __initialize() komponentu. Teraz jest napisane to w ten sposób, że wszystkie argumenty oprócz $options są przekazywane jako tablica do metody __initialize($arguments) i muszę je wyszukiwać według kolejności np. $arguments[0].

Moje pytanie jak zrobić to w ten sposób aby poszczególne argumenty z __construct() były przekazywane w taki sam sposób do metody __initialize() np.w __construct($options = array(), $path, $extension) aby __initializer otrzymał tablicę $arguments = array('path' => 'wartosc', 'extension' => 'wartosc')?