src/SmartFactory/FactoryBuilder.php
static public function bindClass($interface_or_class, $class, $init_function = null)
    {
        if (empty($class)) {
            throw new \Exception("Bound class is empty!");
        }
        
        if (empty($interface_or_class)) {
            throw new \Exception("Bound interface or class is empty!");
        }
        
        if (!interface_exists($interface_or_class) && !class_exists($interface_or_class)) {
            throw new \Exception(sprintf("The interface or class '%s' does not exist!", $interface_or_class));
        }
        
        if (!class_exists($class)) {
            throw new \Exception(sprintf("The class '%s' does not exist!", $class));
        }
        
        try {
            $ic = new \ReflectionClass($interface_or_class);
            $c = new \ReflectionClass($class);
        } catch (\Exception $ex) {
            throw new \Exception($ex->getMessage());
        }
        
        if (!$c->isInstantiable()) {
            throw new \Exception(sprintf("The class '%s' is not instantiable!", $c->getName()));
        }
        
        if ($c != $ic) {
            if (!$c->isSubclassOf($ic)) {
                throw new \Exception(sprintf("The class '%s' does not implement the interface '%s'!", $c->getName(), $ic->getName()));
            }
        }
        
        $f = null;
        if ($init_function !== null) {
            if (!is_callable($init_function)) {
                throw new \Exception(sprintf("'%s' is not a function!", $init_function));
            }
            
            try {
                $f = new \ReflectionFunction($init_function);
            } catch (\Exception $ex) {
                throw new \Exception($ex->getMessage());
            }
        }
        
        self::$itable[$ic->getName()] = ["class" => $c, "init_function" => $f];
    }
static public function bindClass($interface_or_class, $class, $init_function = null)
    {
        if (empty($class)) {
            throw new \Exception("Bound class is empty!");
        }
        
        if (empty($interface_or_class)) {
            throw new \Exception("Bound interface or class is empty!");
        }
        
        if (!interface_exists($interface_or_class) && !class_exists($interface_or_class)) {
            throw new \Exception(sprintf("The interface or class '%s' does not exist!", $interface_or_class));
        }
        
        if (!class_exists($class)) {
            throw new \Exception(sprintf("The class '%s' does not exist!", $class));
        }
        
        try {
            $ic = new \ReflectionClass($interface_or_class);
            $c = new \ReflectionClass($class);
        } catch (\Exception $ex) {
            throw new \Exception($ex->getMessage());
        }
        
        if (!$c->isInstantiable()) {
            throw new \Exception(sprintf("The class '%s' is not instantiable!", $c->getName()));
        }
        
        if ($c != $ic) {
            if (!$c->isSubclassOf($ic)) {
                throw new \Exception(sprintf("The class '%s' does not implement the interface '%s'!", $c->getName(), $ic->getName()));
            }
        }
        
        $f = null;
        if ($init_function !== null) {
            if (!is_callable($init_function)) {
                throw new \Exception(sprintf("'%s' is not a function!", $init_function));
            }
            
            try {
                $f = new \ReflectionFunction($init_function);
            } catch (\Exception $ex) {
                throw new \Exception($ex->getMessage());
            }
        }
        
        self::$itable[$ic->getName()] = ["class" => $c, "init_function" => $f];
    }
static public function bindClass ( $ interface_or_class , $ class , $ init_function = null ) { if ( empty ( $ class ) ) { throw new \ Exception ( "Bound class is empty!" ) ; } if ( empty ( $ interface_or_class ) ) { throw new \ Exception ( "Bound interface or class is empty!" ) ; } if ( ! interface_exists ( $ interface_or_class ) && ! class_exists ( $ interface_or_class ) ) { throw new \ Exception ( sprintf ( "The interface or class '%s' does not exist!" , $ interface_or_class ) ) ; } if ( ! class_exists ( $ class ) ) { throw new \ Exception ( sprintf ( "The class '%s' does not exist!" , $ class ) ) ; } try { $ ic = new \ ReflectionClass ( $ interface_or_class ) ; $ c = new \ ReflectionClass ( $ class ) ; } catch ( \ Exception $ ex ) { throw new \ Exception ( $ ex -> getMessage ( ) ) ; } if ( ! $ c -> isInstantiable ( ) ) { throw new \ Exception ( sprintf ( "The class '%s' is not instantiable!" , $ c -> getName ( ) ) ) ; } if ( $ c != $ ic ) { if ( ! $ c -> isSubclassOf ( $ ic ) ) { throw new \ Exception ( sprintf ( "The class '%s' does not implement the interface '%s'!" , $ c -> getName ( ) , $ ic -> getName ( ) ) ) ; } } $ f = null ; if ( $ init_function !== null ) { if ( ! is_callable ( $ init_function ) ) { throw new \ Exception ( sprintf ( "'%s' is not a function!" , $ init_function ) ) ; } try { $ f = new \ ReflectionFunction ( $ init_function ) ; } catch ( \ Exception $ ex ) { throw new \ Exception ( $ ex -> getMessage ( ) ) ; } } self :: $ itable [ $ ic -> getName ( ) ] = [ "class" => $ c , "init_function" => $ f ] ; }
Binds a class to an interface or a parent class.

The key point of this approach is the definition common interfaces
and implementation of them in classes. When an object that supoorts an
interface is requested, an instance of the corresponding bound class
is created. When you want to change the class, you need just bind
the new class to the interface.

You can also bind a class to itself and reqest it by own name in factory
method. And later, you can implement a derived class and change the binding
without affecting the code in the business logic.

@param string|object $interface_or_class
Name of the class/interface as string or the class/interface.

@param string|object $class
The class which instance should be created if the object is requested.

@param callable $init_function
The optional initialization function. You can provide it to do some
custom intialization. The signature of
this function is:

```php
function (object $instance) : void;
```

- $instance - the created instance.

Example:

```php
FactoryBuilder::bindClass(ILanguageManager::class, LanguageManager::class, function($instance) {
$instance->detectLanguage();
});

FactoryBuilder::bindClass(IRecordsetManager::class, RecordsetManager::class, function($instance) {
$instance->setDBWorker(dbworker());
});
```

@return void

@throws \Exception
It might throw the following exceptions in the case of any errors:

- if the interface or bound class is not specified.
- if the interface or class does not exist.
- if the bound class is empty.
- if the bound class does not implement the corresponding interface.
- if the bound class is not instantiable.
- if the check of the classes and interfaces fails.

@author Oleg Schildt
Binds a class to an interface or a parent class .