bind( $this, get_class($this) );
}
/**
* Binds a concrete implementation to the interface.
* The below is not true as of 2017/03/21, this chain implementation appeared to be mind breaking, so hard to follow
* If several implementations are bound to one interface, it will return the latest one added.
* Then in implementations code they can refer to their own interface, but their own implementation will
* be skipped to avoid circular reference. So it is used like a decorator chain, each implementation can
* refer to an optional parent object of their own interface.
*
* @param string|object $entity A class name or object that implements an interface.
* @param string $interface Optional. An interface to be implemented. If omitted,
* it will require loading the class file to analyze which
* may add an overhead.
* @param bool $singleton Optional. If true then makes the returning object a singleton.
*
* @return object|NULL
*/
public function bind( $entity, $interface = NULL, $singleton = TRUE )
{
if( $interface === NULL ){
$interface = is_object($entity) ? get_class($entity) : $entity;
// $interfaces = class_implements( $interface );
// echo "'$interface' IMPLEMENTS";
// _print_r( $interfaces );
// if( $interfaces ){
// echo "'$interface' IMPLEMENTS ";
// $interface = array_shift( $interfaces );
// echo "'$interface'
";
// }
}
$interface = strtolower( $interface );
// if( is_object($entity) )
// echo "BINDING '" . get_class($entity) . "' AS '" . $interface . "'
";
// else
// echo "BINDING '" . $entity . "' AS '" . $interface . "'
";
// echo "int = '$interface'
";
if( ! is_object($entity) ){
$entity = strtolower( $entity );
}
$this->bind[ $interface ] = $entity;
if( $singleton ){
$this->singletons[ $interface ] = $interface;
}
return $this;
}
/**
* Returns a concrete implementation of the interface with their dependencies injected in constructor.
* Dependencies can be either type-hinted by class/interface name like HC3_Module_ClassName $obj
* or var name hinted, the var name defines the class name, like this $HC3_Module_ClassName
Returns a concrete implementation of the interface with their dependencies injected in constructor.
*
* @return object|NULL A concrete implementation of the interface.
*/
public function make( $interface, $wrap = TRUE )
{
$hooks = NULL;
if( array_key_exists('hc3_hooks', $this->bind) ){
$hooks = $this->bind['hc3_hooks'];
}
else {
$wrap = FALSE;
}
if( 'hc3_hooks' == $interface ){
$wrap = FALSE;
}
$interface = strtolower( $interface );
// echo "WANT '$interface'
";
// echo 'GOTSKIP';
// _print_r( $skip );
// _print_r( array_keys($this->bind) );
$bind_index = 0;
// binded
if( array_key_exists($interface, $this->bind) ){
// echo "INT '$interface' BOUND
";
$thisone = $this->bind[$interface];
if( is_object($thisone) ){
if( $wrap ){
$return = $hooks->wrap($thisone);
return $return;
}
return $thisone;
}
else {
if( ! $thisone ){
if( class_exists($interface) ){
$thisone = $interface;
}
}
$classname = $thisone;
}
}
else {
$classname = $interface;
// try to use a default implementation
// if( substr($classname, -1) == '_' ){
// $classname = substr($classname, 0, -1);
// }
$this->singletons[$interface] = $interface;
}
// echo "REAL '$classname'
";
// _print_r( $classname );
if( ! strlen($classname) ){
$return = NULL;
return $return;
}
$class = new ReflectionClass( $classname );
$constructor = $class->getConstructor();
$dependencies = array();
if( isset($constructor) ){
$need_args = $constructor->getParameters();
foreach( $need_args as $need_arg ){
$is_optional = $need_arg->isOptional();
$wrap_this = FALSE;
$arg_name = $need_arg->getName();
$arg_name = strtolower( $arg_name );
$need_classname = NULL;
try {
if( method_exists($need_arg, 'getType') ){
// $need_class = $need_arg->getType() && !$need_arg->getType()->isBuiltin() ? new ReflectionClass($need_arg->getType()->getName()) : NULL;
$argType = $need_arg->getType();
if( (! $argType) OR $argType->isBuiltin() ){
$argClass = NULL;
}
else {
if( method_exists($argType, 'getName') ){
$argClassName = $argType->getName();
}
else {
$argClassName = '' . $argType;
}
$argClass = new ReflectionClass( $argClassName );
}
$need_class = $argClass;
}
else {
$need_class = $need_arg->getClass();
}
}
catch( ReflectionException $e ){
$need_class = NULL;
}
if( $need_class ){
$need_classname = $need_class->getName();
}
if( ! $need_class ){
if( ! $is_optional ){
$need_classname = $arg_name;
$wrap_this = TRUE;
// echo "NOW NEED CLASSNAME = '$need_classname'
";
}
}
if( $is_optional && (! $need_classname) ){
continue;
}
if( (! $need_classname) && (! $is_optional) ){
echo "DIC: class/varname is unknown for '$arg_name' argument of '$classname'!
";
exit;
}
if( $need_classname ){
$need_classname = strtolower( $need_classname );
if( ! array_key_exists($need_classname, $this->bind) ){
// if( $is_optional ){
// continue;
// }
// else {
// echo "DIC: class '$need_classname' is not registered while trying to use it as a dependency for '$classname'
";
// exit;
// }
}
$dependencies[] = array( $need_classname, $wrap_this );
}
}
}
if( $dependencies ){
$args = array();
foreach( $dependencies as $dep ){
list( $dep, $wrap_this ) = $dep;
if( ! is_object($dep) ){
$dep = $this->make($dep, $wrap_this);
}
$args[] = $dep;
}
$class = new ReflectionClass($classname);
$return = $class->newInstanceArgs($args);
}
else {
$return = new $classname;
}
if( isset($this->singletons[$interface]) ){
// echo 'REBIND ' . $interface . ' AS ' . get_class($return) . '
';
// echo 'BIND INDEX = ' . $bind_index . '
';
// _print_r( $this->bind[$interface] );
// $this->bind( $return, $interface );
$this->bind[ $interface ] = $return;
}
if( $wrap ){
$return = $hooks->wrap($return);
}
else {
// echo "NO WRAP FOR " . get_class($return) . "
\n";
}
return $return;
}
}