Looser coupling

I would really like to see looser coupling in Yii 2.0, for example in CActiveRecord::getRelated() half way down the method we have $finder = new CActiveFinder($this,$r) - what if we want to use a different active finder class? we’ll have to override the whole method. What if we want to test the current code using mock objects? we can’t. To me it would be better to have this object instantiation in it’s own method, e.g. $finder = $this->createActiveFinder($this,$r). This makes it easy to switch individual components without having to copy and paste huge swathes of code. Ideally we would do this everywhere we create an object.

Don’t know how easy to use it would be but could do something similar to jQuery.




test(array(

    'func' => function() {echo 'test';},

));

    

function test($config)

{

    $config = array_merge(array(

        'func' => function() {echo 'target';},

    ), $config);

    $config{'func'}();

}



Would allow you to override certain bits.

I agree. I think this issue was already adressed here: http://www.yiiframework.com/forum/index.php?/topic/21692-component-creation

Here’s a 30 second example implementation:




class CComponent {

    /**

     * Holds a map of component class names that should be used when instantiating child components.

     * e.g.

     * <pre>

     * array(

     *      "CActiveRecord" => "CustomActiveRecordClass"

     * )

     * </pre>

     * @var array

     */

    protected $_componentMap = array();


    /**

     * Registers a component class

     * @param string $baseClass the base class name

     * @param string $realClass the name of the real class to instantiate

     */

    public function registerComponent($baseClass, $realClass) {

        $this->_componentMap[$baseClass] = $realClass;

    }

    /**

     * Unregisters a component class

     * @param string $baseClass the name of the base class to unregister

     */

    public function unregisterComponent($baseClass) {

        unset($this->_componentMap[$baseClass]);

    }

    /**

     * Creates a component with the given name.

     * @param string $name the name of the component to instantiate

     * @param mixed $arg1... the arguments to pass to the component constructor

     */

    public function createComponent($name, /* $arg1, $arg2 */) {

        if (isset($this->_componentMap[$name])) {

            $name = $this->_componentMap[$name];

        }

        $arguments = func_get_args();

        array_shift($arguments); // we don't need the first one

        array_unshift($arguments,$name);

        return call_user_func_array(array("Yii","createComponent"),$arguments);

    }

    

}



You could then use it like:




class Blah extends CComponent {

   public function doSomething() {

       $map = $this->createComponent("CMap");

       $map["greeting"] = "Hello world";

       return $map;

   }

}


$test = new Blah;

$test->registerComponent("CMap","CAttributeCollection");

$this->assertTrue($test->doSomething() instanceof CAttributeCollection);



On topic of loose coupling - this should be added with great care. Yii was designed more solid on purpose - to be fast and provide easy usage. Loose coupling is more powerful for sure, but also more complex and has much more overhead. Not to mention the ability to shoot yourself in a leg (for obvious reasons that will happen with people more times that you could think of).

So I semi-support this proposal - in some cases it is a good think, but the framework should not become a library - we have it all ready in Zend and Symphony 2 incarnation. Why make another version of it?

Many select Yii because it’s easier to work with, it’s more integrated and due to that you have to write less code, because components are aware of each other. And we need such kind of instrument. Because, well, Yii fits the needs for 99.9% of tasks we do. And if we stumble upon the need for that 0.1% - usually you can do that without hacking into the Yii code - just replace the component with our own version, maybe make a patch and try to get that into the framework itself (worked for me a few times -i’m a happier PHP developer now).

For god’s sake, the reality is that in everyday work I don’t want to make my tasks complex. I don’t want to deal with loose coupling - I just don’t want to write tons of components with loose coupling and other OOP-guru-freak stuff. I just don’t need that - most things I write are unique to the project and will not, and frankly - can’t, be reused without modification. And generic things are all ready written in reusable way in form of extensions and modules.

I believe SamDark shares my point of view in this matter and I believe it to be reasonable. Also I strongly believe in the KISS principle and every time I see someone trying to get some overly complex thing into PHP - I shout at those people at the dev mailing list. Same thing here.

i said looser, not loose :)

I don’t want to see Yii2 become as verbose as Zend or Symfony either, but there are scenarios where we do want to switch out the object being created by the framework. I agree that this would add overhead (quite how much is yet to be tested) but my first example using dedicated methods to create the object would hardly introduce any overhead at all and would still allow some flexibility.

I’m advocating this at the framework level, no one would force you to use this syntax, new Blah() would still work in your application code.

phpnode

Better to be overly cautious than not enough :)

I chose Yii after using CakePHP because Yii is much faster.

I believe it has to do with the fact that Yii is not using as much magic sauce as CakePHP does.