如何告诉Registry Object如何有效地在PHP中创建对象?

时间:2013-10-20 19:46:38

标签: php oop design-patterns

我正在创建一个对象注册表来轻松检索对象并处理全局对象(我只需要一个实例的对象,比如围绕wp_functions或工厂的包装器) 基本上我有各种各样的场景要处理。

1)我需要创建的对象是一个简单的类 2)我需要创建的对象是一个简单的类,但不需要不同的实例 3)我需要创建的对象是由工厂创建的 4)我需要创建的对象需要一些参数。

这是我的代码

<?php

/**
 * @author nicola
 *
 */
class Ai1ec_Object_Registry implements Ai1ec_Registry_Interface {

    CONST PREFIX = 'Ai1ec_';

    static private $_objects = array();

    static private $_classes = array();

    /**
     * (non-PHPdoc)
     *
     * @see Ai1ec_Registry_Interface::get()
     *
     */
    public function get( $key ) {
        $classname = $this->get_classname();
        if( ! isset ( self::$_classes[$classname] ) ) {
            throw new Ai1ec_Registry_Exception( 
                'The class "' . $classname . '" was not registered'
            );
        }

        $options = self::$_classes[$classname];
        // if it's a global object and it's already set, return it
        if ( isset( $options['global'] ) && 
                isset( self::$_objects[$classname] ) ) {
            return self::$_objects[$classname];
        }
        $params = array();
        if( func_num_args() > 1 ) {
            $params = func_get_arg( 1 );
        }
        // check if the object needs a factory
        if ( isset( $options['factory'] ) ) {

            return $this->dispatch( 
                $options['factory'][0],
                $options['factory'][1],
                $params
            );
        } else {
            if ( empty( $params ) ) {
                return new $classname();
            } else {
                $class = new ReflectionClass( $classname );
                return $class->newInstanceArgs( $params );
            }

        }

    }

    /**
     * (non-PHPdoc)
     *
     * @see Ai1ec_Registry_Interface::set()
     *
     */
    public function set( $key, $val ) {
        if ( ! is_object( $val ) ) {
            throw new Ai1ec_Registry_Exception( 'Only Objects can be stored in the registry' );
        }
        $classname = $this->get_classname();
        if ( isset( self::$_objects[$classname] ) ) {
            throw new Ai1ec_Registry_Exception( 'Only one object for each key is allowed' );
        }
        self::$_objects[$classname] = $val;
    }

    /**
     * Register a class into the registry
     * 
     * @param string $class_name The name of the class to registr
     * @param array $options     An array of options about the class.
     */
    public function register( $class_name, array $options ) {
        if( isset( self::$_classes[$class_name] ) ) {
            throw new Ai1ec_Registry_Exception( 'A class can\'t be registered twice' );
        }
        self::$_classes[$class_name] = $options;
    }

    /**
     * A call_user_func_array alternative.
     * 
     * @param string $class
     * @param string $method
     * @param array $params
     * 
     * @return mixed
     */
    public function dispatch( $class, $method, $params = array() ) {
        // get an instance of the class
        $class = $this->get( $class );
        switch ( count( $params)  ) {
            case 0:
                return $class->{$method}();
            case 1:
                return $class->{$method}( $params[0] );
            case 2:
                return $class->{$method}( $params[0], $params[1] );
            case 3:
                return $class->{$method}( $params[0], $params[1], $params[2] );
            case 4:
                return $class->{$method}( 
                    $params[0], 
                    $params[1], 
                    $params[2],
                    $params[3]
                 );
            case 5:
                return $class->{$method}(
                    $params[0],
                    $params[1],
                    $params[2],
                    $params[3],
                    $params[4]
                );
            default:
                return call_user_func_array( array( $class, $method ), $params );
        }
    }

    /**
     * Return the class name from the key.
     * 
     * @param string $key
     * 
     * @return string
     */
    private function get_classname( $key ) {
        return self::PREFIX . $key;
    }
}

它应该处理所有情况,但这是最好的方法吗?这不会引入太多开销吗?

0 个答案:

没有答案