4
\$\begingroup\$

I am currently working on a class to make objects and vars available to child classes while attempting to avoid a singleton. Each child with dependencies extend this class and pass params (var names) of required dependencies. If parent construct is called and params is empty full registry is set.

Example of Registry:

class Registry {   
public static $registry = []; 

public function __construct($DI = '') {
    if (self::$registry) {

        /**
         *  $DI List Missing Pass Entire Registry
         */
        if (!$DI) {
            foreach (self::$registry as $var => $value) {
                $this->$var = $value; 
            }
        }

        /**
         *  $DI List Set, Pass Specific Dependencies
         */
        else {
            foreach ($DI as $dependency) {

                    if (isset(self::$registry[$dependency])) {
                        $this->$dependency = self::$registry[$dependency];
                    } 
                    else {
                        if (ENVIRONMENT == 'development') {
                            echo get_called_class().' Needs Dependency '.$dependency.'<br /><br />';
                        }
                    }

            }
        }
    }
}  


/**
 *  Add to Registry
 */
public static function add($array, $type = 'class', $namespace = '') {
    foreach ($array as $var => $value) {
        if (!isset(self::$registry[$var])) { 

            switch ($type) {
                case 'class':
                    $class                  = $namespace.$value;   
                    self::$registry[$var]   = new $class; 
                    break;

                case 'var':
                    self::$registry[$var]   = $value;
                    break;
            }  

        }
    }
}


private function __clone() {}
private function __wakeup() {}
}

Adding and using vars/objects from registry is easily done through static calling, but the main point of this class is to pass dependencies to child classes. I am wondering if there are drawbacks that someone with more experience would know of/find.

\$\endgroup\$
1
\$\begingroup\$

I think the proposed solution is bad. There is no room for lazy loading. All dependencies need to be defined for this 'registry' class. The registry class thus becomes all knowing. All other classes extend Registry, thus are all knowing as well. If you think that is no problem? then stop reading and continue

Another problem: objects are passed around by reference, vars are copied. Is this desired?

What if the $class needs different parameters set depending on where it is used?

Lets look at the following situation: Both the database and the mailer need a LoggerInterface. So they have a dependency of 'LoggerInterface'. The database however logs to a file, and the Mailer logs to the database. How do you solve this? Have the Mailer depend on a DatabaseLogger?

So to be able to use your Registry, we can no longer hint for generic interfaces, but we hint for concrete classes.

\$\endgroup\$
  • \$\begingroup\$ I would not be using this to load every single class dependency throughout the site. The main point of it is to make core classes available where needed without having to pass through a variety of dependencies within the child construct. ithin my bootstrap file the core classes are set ( db, log, sessionHandler, etc. ). If i was in need of a specific class within another i will just instantiate it within that class ( ie your LoggerInterface example ). Is there another alternative that comes to mind? The core classes are necessary in all models and half of them are required for controllers. \$\endgroup\$ – ICJ Dec 12 '14 at 16:35
  • \$\begingroup\$ If the core classes are needed in all models, then you should go back to the design board. \$\endgroup\$ – Pinoniq Dec 12 '14 at 19:42
  • \$\begingroup\$ I meant that the other way around -_- Late night. \$\endgroup\$ – ICJ Dec 13 '14 at 0:56
  • \$\begingroup\$ MAybe look into how Symfony handles a PAgeRequest. This is a good start imo. That one helped me a lot. symfony.com/doc/current/components/http_kernel/… \$\endgroup\$ – Pinoniq Dec 13 '14 at 12:10
1
\$\begingroup\$

Your problem is a bit simple to be achieved. Take a look at some "Dependency Injection" project/class and you wil need Register classes anymore.

The best way to avoid high couple in classes is to create clean/naked classes with no dependencies (eg. inheritance, new instances inside methods or constructors).

You need to create all the dependencies a part of the client (consumer) classes and use them later by constructor/setter injection :

<?php
class DbConn //I do not have inheritance here
{
    function exec($sql)
    {
        //do some db work
    }
}

class UserDAO //I do not have inheritance here
{
    function __construct(DbConn $conn) // I injected my needed dependency here
    {
        $this->conn = $conn; //I set my conn here
    }

    function insert(User $user) // I do not like to use arrays =)
    {
        $sql = "insert into users (...) values ('{$user->getName()}')"; 
        return $this->conn->exec($sql);
    }
}
?>

After all you need to solve your dependencies:

<?php
$conn = new DbConn($someAuthData);
$user = new User("yourname");
$userDao = new UserDAO($conn);

$userDao->insert($user); //tan nan nan nan
?>

On the above example I just needed a simple injection to solve the dependency issue. But... when we have complex dependency graph we need to use a container.

So... again, I say to you take a look at some Dependency Injection project:

There is some of them here: http://www.sitepoint.com/php-dependency-injection-container-performance-benchmarks/

Cheers

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.