• What is Sphicy?

    Sphicy helps you to create your objects in a reasonable way. It makes use of the dependency injection pattern. Its architecture is loosly based on Google's Guice framework.

  • What is dependency injection?

    In an application each object has dependencies with other objects. Dependency injection (DI) simply states that these dependencies shall be made explicit. If class A depends on class B, then the constructor of A should require an object ob B to be created. In a perfect world of DI all dependencies are given through the constructor. As alternative setters methods are possible which are enforced to be called after object creation.

  • So how does Sphicy work?

    Sphicy has 4 terms that describe its functionality:

    1. A module configures which concrete implementation should be bound to which interface.
    2. The binder collects all configured bindings.
    3. An injector works with a module to instantiate objects and inject the appropriate dependencies into their constructors.
    4. A provider contains and offers functionality to retrieve class or object implementations of bound interfaces.

    To use Sphicy you would create your own concrete module implementation and have the injector and binder tie it all together to instantiate the objects you want to have.

  • Show me an example of how Sphicy works

    Imagine we have remote and it always has a device it depends on. We have to interfaces describing this world:

    interface Remote {
        public function __construct(Device $device);
        public function pressButtonOn();
        public function pressButtonOff();
        public function getDevice();
    }
    interface Device {
        public function switchOn();
        public function switchOff();
    }

    Now if you have to concrete implementations TVRemote and TV you would always have to instantiate a TV and put it into the TVRemote constructor to get your remote. Sphicy extracts this dependency graph into a module, that can be reused throughout your application to build TVs:

    class MyTelevisionModule implements spModule {
        public function configure(spBinder $b)
        {
            $b->bind("Remote")->to("TVRemote");
            $b->bind("Device")->to("TV");
        }
    }

    Retrieving your Remote object would then look like:

    $injector = new spDefaultInjector(new MyTelevisionModule());
    $remote = $injector->getInstance('Remote');
  • How does one use multiple concrete implementations of one interface?

    There are different possibilites to handle multiple concrete implementations:

    1. You can add different modules, if you know upfront which assembling strategy you need.
    2. You can use named annotations to hint Sphicy which implementations are preferred.
    3. You can make use of the concept of Providers. Instead of binding an interface to one single instance, you can bind it to a provider. The provider can decide based on the argument list or other circumstances, which concrete object is needed now.
  • How do annotations work in Sphicy?

    You can bind certain interfaces to annotations rather than the interface name itself. When you try to create an object and explicitly state that you want to use an annotation, this annotation is given deep down to all dependencies.

    You could also use the specific doc-block syntax and put @annotate $paramName annotationName into it.

  • I cannot grasp those Providers, please give an example!

    You can bind a provider to a specific interface. The provider has to implement the interface spProvider and requires one method get($name, array $args, $annotation) which you can implement. This is the way to create specialized factories within Sphicy.

    Say you have a module which binds an interface to a provider:

    class MyDeviceProviderModule implements spModule {
        public function configure(spBinder $b)
        {
            $b->bind("Device")->toProvider(new MyDeviceProvider());
            $b->bind("Remote")->to("UniversalRemote");
        }
    }
    class MyDeviceProvider implements spProvider
    {
        public function get($name, $args)
        {
            if($args['type'] == "TV") {
                return 'MyTV';
            } elseif($args['type'] == "DvdPlayer") {
                return 'MyDvdPlayer';
            } else {
                throw new spProviderException;
            }
        }
    }

    Now we can decide upon which device is instantiated by calling:

    $injector = new spDefaultInjector(new MyDeviceProviderModule());
    $tv  = $injector->getInstance('Device', array('type' => 'TV'));
    $dvd = $injector->getInstance('Device', array('type' => 'DvdPlayer'));

    The MyDeviceModule implementation looks tedious but some complex cases of dependency injection might need such a setup.

    Additionally you could use Providers as wrappers around existing factories or assembling stratgies of your own code basis or frameworks that you are using. Additional uses cases would be configuring persistent objects.

    Objects that use setter injection can also be created by providers, like this example shows:

    class myPersistentObjectProvider implements Provider {
        public function get($name, $args) {
            $object = new MySetterObject();
            $object->setStuff($args["stuff"]);
            $object->setFoo($args["bar"]);
            return $object;
        }
    }

    As you can see, Providers can return either strings of class names or objects as their target implementation.

  • How can factory relations be depicted in Sphicy?

  • How can the Abstract Factory Pattern be implemented with Sphicy?

  • Does Sphicy support some form of staging like production/development?

  • Can I combine different modules in one injector?

  • How can I ensure an object is only created once (Singleton)?

    Sphicy allows to have single instances across the object tree without the need for static, global singletons.

    You can make use of the binding to an instance, so that this instance is used as placeholder for all "Interface" implementations.

    class MySingletonInstanceModule implements spModule {
        public function configure(spBinder $b) {
            $b->bind("Interface")->toInstance(new Instance());
        }
    }

    This case is only useful for singletons that are leafes in the object graph. When the singleton should create more objects deep down that might even be singletons on their own in other parts of the graph you have to use the following nice solution:

    class MyEagerSingletonModule implements spModule {
        public function configure(spBinder $b) {
            $b->bind("ArrayAccess")->to('ArrayObject').asEagerSingleton();
        }
    }

    Now the ArrayObject is instantiated upon first request and buffered in a layer inside the injector. If you use this injector to request more implementations of ArrayAccess it will always return the single instance that was created earlier.

    This is by far the most beautiful way to use a singleton instance without having to use the Singleton pattern with global static accessors. You can use exactly the same object in two very different positions of the object graph without having to pass it around through all its intermediates.

  • How can I pass additional simple types like Integers or Arrays into constructors?

    First a note: Sphicy works best with constructors that require only objects as arguments.

    The second argument of the getInstance() injector method allows to pass arguments as key value pairs of "argument variable name" and "argument value".

    $injector->getInstance("Interface", array("argName1" => "argValue1"));

    This argument list is passed down to nested getInstance() calls.

  • How can I configure my dependencies via a config-file/database?

    You can write a custom module that accepts the configuration parameters and implement binding decisions based on this information.

  • How do optional parameters in constructors work with Sphicy?

    If an object allows to be passed in as "null" and no concrete interface binding is found Sphicy will automatically detect this and insert null as parameter.

  • I am using framework X, can i use Sphicy to build its dependencies?

    If the framework is engineered with good OO-practices in mind you are probably possible to use Sphicy. Sample framework modules for Sphicy will be implemented sooner or later.

    If you have build a module for Sphicy that helps bootstrap framework dependencies you can of course contribute this back to be included in Sphicy by default as a TieIn component.

  • Isn't Sphicy hurting performance a lot?

  • What features are still missing in Sphicy?

    1. Implement the notion that each Class and Interface is bound to itsself by default and the binder only redirects those default bindings. This allows instantiating implementations via the injector and load its dependencies through Sphicy.
    2. Implement binding of constant parameters in a module with binder.
    3. Implement annotation for default implementation of an interface to reduce coding overhead.
    4. Supporting setter injecting via an annotation in the class constructor that points to all methods that are setter methods, for example: @setters setFoo setBar setBaz.