The Clean Code Talks - Don't Look For Things!

By: GoogleTechTalks

1127   31   207963

Uploaded on 11/08/2008

Google Tech Talks
November 6, 2008

ABSTRACT

Clean Code Talk Series
Topic: Don't Look For Things!

Speaker: Misko Hevery

Comments (20):

By anonymous    2017-09-20

Instead of that dreadful abomination, you should learn how to utilize spl_autoload_register():

spl_autoload_register( function( $classname ){

    $filename = 'inc/classes/' . $classname . '.class.php';

    if ( !file_exists( $filename) ){
        throw new Exception("Could not load class '$classname'.". 
                            "File '$filename' was not found !");
    }

    require $filename;

});

And you should register the autoloader in your index.php or bootstrap.php file, and do it only once per loader (this ability lets you define multiple loaders, but that's used, when you have third party library, which has own autoloader .. like in case of SwiftMailer).

P.S. please learn to use prepared statements with MySQLi or PDO.

Update

Since you are just now learning OOP, here are few things, which you might find useful:

Lectures:

Books:

Original Thread

By anonymous    2017-09-20

First question:

The first problem happens because you are loading and rendering the view files IN the action context/scope of the controller. That's why your url in the point 3. is "incorrect", e.g. site-test/tasks/page/tasks, e.g '///`. So, other said, because you are actually seeing the rendered html content from inside the controller folder, where it was the view file rendered.

In order to resolve this you have to options:

Option 1) Use absolute paths in all the anchors in your view/template files, like for example:

<a href="http://site-test/tasks/">tasks</a>
<a href="http://site-test/tasks/page/2">next page</a>

Here you can of course use a variable in your view/template files instead, like:

<a href="<?php echo $host; ?>/tasks/">tasks</a>
<a href="<?php echo $host; ?>/tasks/page/2">next page</a>

I showed you just pure php code, but you can use syntaxes provided by a diversity of template engines, if you decide to use one, one then PHP engine.

Option 2) Use relative paths in all the anchors in your view/template files, like for example:

<a href="/tasks/">tasks</a>
<a href="/tasks/page/2">next page</a>

The key is of course the slash (/) at the beginning of each anchor's href attribute. It ensures that all the links are "joined" to the host http://site-test of your MVC website.

Personally I use the second option in my own MVC framework and it works smooth and is... pretty.

Second question:

When url is: site-test or site-test/tasks all files loading from root_directory/images or root_directory/css, when url is: site-test/tasks/page/2 he tries to find these files in root_directory/tasks/page/images

Well, here is the need of a discussion:

When url is site-test, then the default action of the default controller is called, e.g. Controller_add_task::action_index(). You didn't show the code for that controller, so I can't say nothing about from where and how are the asset files (css, images, js) loaded in the views.

Same goes for the url site-test/tasks/page/...: you showed the code for the controller, but I can't say nothing about how and where are the asset files (css, images, js) loaded in the views. Are the asset paths loaded from inside the Controller (parent class) methods? Are they written - as normal - in the view/template files (using <script src=...>, <link href=...>, <img src=...>)? Are they loaded from inside the View::generate?

In principle, they can be passed to the view/template files as variables, or they can be written - as normal - in the view/template files.

The context/scope theory of the first question applies here too. And the key here is the same as in the first question: the asset paths should be passed/written as absolute paths or relative paths as shown above in the options 1) and 2).

Recommendations:

Note: Seeing that you want to learn clean MVC, I thought you would allow me to give you some tips:

*) Don't use any static classes/functions, singletons or so called service locators. Trust me, you don't need them at all if you are writing a clean, good testable MVC.

*) Use a dependency injection container like Auryn, which you will implement only on the entry point of your app, e.g. bootstrap.php or index.php. The next point tells you why.

*) Inject your dependencies, don't create them in the places where they are needed. So not like this:

function __construct()
    {
        $this->model = new Model_tasks();
        $this->view = new View();
    }

but like this:

function __construct(Model_tasks $model, View $view)
    {
        $this->model = $model;
        $this->view = $view;
    }

Read:

*) Use namespaces! Read PSR-4: Autoloader (yes, it's correct).

*) Read all the first 8 recommendations in PHP Standards Recommendations. They are very important if you want to correctly learn how to develop a PHP MVC.

*) Learn the five SOLID principles in OOP (just search for "solid principles" in web).

*) Use a corresponding view class for each controller class (1:1). For example: if you have TasksController, then also create a class TasksView. And what you are using there as view files - tasks_view.php, template_view.php, etc - are actually template files. And you should implement a Template class, which is to be injected in the corresponding view class. The template class is actually responsible for rendering/loading the template files. The view class should be responsible to output the rendered content (or to pass it to a Response class to be outputed).

Read: Understanding MVC Views in PHP

*) Don't use names like Controller_tasks for the class names. Use the syntax like this - I forgot the name: TasksController, TasksModel, TasksView.

*) Don't use names like action_index for the class methods or members. Use the camelCase syntax. And don't use action in the controller methods, because you already know that. So write the methods just like this: index(), page(), listBooks. If you use ajax you can name them like ajaxGetUsers(), etc. Just make sure that your routing system make the correct syntax-mapping between the controller/action names in url and the actual controller/action names.

Resources:

Good luck.

Original Thread

By anonymous    2017-09-20

Your question is:

Inside a class, can I create instances of other classes?

Well, theoretical and technical, you can easily receive the answer "yes". But the real answer is... "no". Because, if you do it:

  • you are tightly coupling the class in which the instances are created (Car) to the classes from which the instances are created (Engine, Wheels, FuelTank). This way, a car will always must have a fuel tank, even though there could be implemented an electrical power only solution.
  • the car will not only have the responsibility to go on a road, but to create its car parts by itself, too. And this is somehow... "Transformers"-like.

But, if you want to correctly learn and apply OOP, then these two situations are not a "permitted" option. It's the same as: in a normal swimming competition you could use a pair of fins, but you would be desqualified.

That said, the only viable alternative to tight coupling is the loose coupling: the car parts are injected, e.g. passed, e.g. plugged into the car. In OOP, this process has the name dependency injection (DI). The car parts - the dependencies - can then be easily changed, or removed. So, the fuel tank can then be completely removed, because the car will be driven only with electrical power. The car itself has now the single responsibility of going on a road. And, even if it still depends on its parts - as it should, the car is not anymore concerned with the process of car parts creation: it just receives them - as it should.

I just realised, that I'd use another conceptual scheme: an Engine should not be a CarPart. Only the fact that it's plugged into a car makes it a car part. The same goes for the Wheels and FuelTank. In short, I'd define them in other way:

class Engine {...}
class Wheels {...}
class FuelTank {...}

class CarEngine extends Engine {...}
class CarWheels extends Wheels {...}
class CarFuelTank extends FuelTank {...}

So, the loose coupling will be applied like this:

class Car{

    Car(instance of CarEngine, instance of CarWheels, instance of CarFuelTank){
        //...
    }

}

or, even better, in analogy with your code version:

class Car {

    Car(instance of Engine, instance of Wheels, instance of FuelTank){
        //...
    }

}

Here are two wonderful resources for a better understanding of the principles presented here:

Good luck with your projects!


EDIT 1:

@Ryan The Leach kindly and rightly proposed me to also present you the notion/concept of factory. I'll try to do it in a principle manner.

The car needs an engine to be able to function. But who could produce this car part? Well: an engine factory. More precisely a car engine factory.

In terms of OOP, a factory is a specialized class having a single responsibility: the creation of instances of other classes (sounds familiar?). The created instances are then used somewhere else, according with their usefulness. Now, when a factory creates an object, or more objects of different class types, it may need to gather/produce other resources too, in order to prepare the creation of the final "product(s)".

So, an engine factory would first need to gather/produce a lot of engine pieces before assembling/creating the final engine. The same applies to a car factory: it needs to receive an engine from the engine factory, wheels from the wheels factory and a fuel tank from the fuel tanks factory. Then it produces the final cars.

In OOP, there are three types of factories, e.g of so called factory patterns:

  • The simple factory
  • The factory method and
  • The abstract factory.

I'll not present them here personally, but I'll try to direct you to some (very) good web resources, easy to follow and understand:

P.S:

The first two are my favorites... although I didn't watched them yet :-) Yes, silly, isn't it? Because they are relative new uploads I didn't knew that they exist. BUT: I followed all the other streams of the author and, in three words: I was impressed. Nota bene: the author explains all the patterns presented in the book "Head First Design Patterns".

Original Thread

By inglor    2017-09-21

I'll try to elaborate, global _app_ state is different from global state "in the wild".

The internet is "global state" but you wouldn't call any code that makes HTTP requests global state because the "globality" is isolated inside your app.

Global can mean several things, my point was only that "globality" inside your app can (and should) be very constrainted while acknowledging some things are indeed global from your app's point of view. A good example of this is having a global "db" object vs. a DB instance passed to places.

This is more about whether or not your code should care about where it gets data or not. I think this (now classic) talk is a nice explanation about why your components should not "look for things" in the global but instead should be explicit about dependencies any why it's easier to reason about: https://www.youtube.com/watch?v=RlfLCWKxHJ0

Original Thread

By anonymous    2017-09-23

You are doing quite a lot things wrong there.

Don't wrap PDO class

PDO already is a DB acces abstraction. You do not need to abstract the abstraction. You are also doing the prepared statements wrong in your code, which makes your code vulnerable to SQL injections. Please check the linked manual article and pay specific attention to use of bindParam() and bindValue() methods. You could also watch this video (it's uses mysqli in the examples, but the core mechanic is the same), which should explain where to injection vulnerability actually comes from.

Use dependency injection

Your current code relies on the global state. Instead you should inject the PDO instance as a dependency in your Settings service.

In practice it would looks something like this:

class Setting {
    privare $connection;

    public function __construct(PDO $connection) {
        $this->connection = $connection;
    }

    public function options($option_name) {
        // codes here
    }
};

The idea basically is:

$db = new PDO;
$foo = new Foo($db);
$bar = new Bar($db);

This way the both Foo and Bar instance have the same DB connection.

Watching this lecture would be highly recommended.

Original Thread

By anonymous    2017-09-23

https://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=youtu.be

Original Thread

By anonymous    2017-09-23

Let's look at the real life example. Let's say you have a car. Car needs an engine.

class Car
{
    private $engine;

    public function __construct()
    {
        $this->engine = new V6Engine();
    }
}

The car has a dependency on the engine. In this case, the car itself needs to construct a new engine! Does it make sense? Well.. NO! Also, the car is coupled to the specific version of the engine.

This makes more sense. Someone else needs to provide the car engine. It could be some engine supplier, engine factory... It is not car's job to create engine!

class Car
{
    private $engine;

    public function __construct(Engine $engine)
    {
        $this->engine = new $engine;
    }
}


interface Engine
{
    public function start();
}

class V6Engine implements Engine
{
    public function start()
    {
        echo "vrooom, vrooom V6 cool noise"
    }
}

Also, you could easily swap the engine, you are not coupled to the specific engine. That new engine only needs to be able to start.

Martin Fowler has written a very good article about the inversion of control and dependency injection.

https://martinfowler.com/articles/injection.html

Please read it - because he will explain the DI much better than I can do :)))

Also, there is very good video by the Miško Hevery "The Clean Code Talks - Don't Look For Things!". You will be much clever after watching it :)

https://www.youtube.com/watch?v=RlfLCWKxHJ0

Original Thread

By anonymous    2017-10-22

Here are some very good resources to study. They will give you the answer to the question "How can I make it right?". [The Clean Code Talks - Don't Look For Things!](https://www.youtube.com/watch?v=RlfLCWKxHJ0), [PHPNW15: James Mallison - Dependency Injection and Dependency Inversion in PHP](https://www.youtube.com/watch?v=Ojsn11XY0X8&feature=youtu.be), [Managing Class Dependencies: ..., Part 1](https://www.sitepoint.com/managing-class-dependencies-1/), [Managing Class Dependencies: ..., Part 2](https://www.sitepoint.com/managing-class-dependencies-2/),

Original Thread

By anonymous    2017-10-30

See: [YouTube: Clean Code Talks](http://www.youtube.com/watch?v=RlfLCWKxHJ0).

Original Thread

By anonymous    2017-10-30

Ishegg is right. Here are two very good resources which sustain and explain what he says: [The Clean Code Talks - Don't Look For Things!](https://www.youtube.com/watch?v=RlfLCWKxHJ0) and [James Mallison - Dependency Injection and Dependency Inversion in PHP](https://www.youtube.com/watch?v=Ojsn11XY0X8&feature=youtu.be).

Original Thread

By anonymous    2017-10-30

A good answer! ;-) Just a note though: the "OK" version I would directly entitle as "BAD" (regarding config array and tight coupling): [The Clean Code Talks - Don't Look For Things!](https://www.youtube.com/watch?v=RlfLCWKxHJ0) and [James Mallison - Dependency Injection and Dependency Inversion in PHP](https://www.youtube.com/watch?v=Ojsn11XY0X8&feature=youtu.be).

Original Thread

By anonymous    2017-11-06

I am learning the popular MVC and trying to implement it in PHP. I am designing a framework with a pure OOP fashion (though I am not expert in PHP's OOP ability. I only have moderate knowledge about it). An example implementation of this framework as shown in the following figure. enter image description here

In this framework I added a Data Access Layer, DAL, (a class to deal with the connection, executing query and transport to and from the database) to abstract the physical database from the rest of the system to easy change of the data source. If a system is only bind to one database of one particular type, this layer is expected to presented in the system using only one object with one connection to the database. And this object will be a dependency for all the Data Mapper objects (i.e., User mapper, Product Mapper).

I am looking for your comments on where to initiate the DAL object in the system. I can create the object in the front controller (index.php) and transport all the way to Data Mapper objects. But it is an anti-pattern according to Here and Here. Even for the same reason, we cannot initiate the DAL object within the factories (Factories can be separated in multiple classes for handling complexities as per Clean code approach ). I cannot use Singleton as that is also going to create lots of problem according to this. So, in your opinion, what is the best practice and place where I can initiate this object and pass it to Data Mapper objects?

N.B.: I disregard the View Logic here as my concern do not have any relation with Views.

Original Thread

By anonymous    2018-02-05

@bnoeafk ;-) There are "_dependency injection_" and "_dependency inversion_" in OOP. Check [this](https://www.youtube.com/watch?v=Ojsn11XY0X8&feature=youtu.be) and [this](https://www.youtube.com/watch?v=RlfLCWKxHJ0) out. So, you must avoid tight coupling in your classes design. E.g. don't create an object inside of a class, but pass it as dependency (e.g. as constructor or setter argument). Also, as a little (but important) note: the **variables** defined in a function definition are called "_parameters_". The **values** passed when the function is called are named "_arguments_".

Original Thread

By anonymous    2018-02-18

Static, singleton, global

I am sorry to disappoint you, because I am sure you invested a lot of effort in your code,... but you could or should take in consideration to start by not using any static methods (nor singletons or global variables). Here and here are some reasons presented.

Dependency injection (DI)

Inside a class, don't use methods of another class to create instances. If you need an object of any type, inject it - in constructor, or in any other method that needs it. This is called dependency injection. See this and this.

So, you should have this (further below I will change it):

class LoginController {

    private $template;

    __construct(Template $template) {
        $this->template = $template;
    }

    public function getView() {
        $this->template->renderTemplate('index.html');
    }

}

Dependency injection container (DIC)

The structure that has the responsibility of injecting dependencies (e.g. wiring) is called dependency injection container (DIC). Examples: PHP-DI, or Auryn). It is constructed and used only at the entry point of your app (like in index.php or bootstrap.php). In it you will register your app dependencies, and it will automatically take care of injecting them all over. Your App class would then be redundant. And your application will "concentrate" itself on its actual purpose, not on the creation and/or implementation of the structures that it requires in order to be able to complete its tasks. The related term is Inversion of Control (IoC).

Service locator

As a note: don't pass the DIC as dependency. If you do that you are "creating" a so called service locator. It would mean that your class would depend on the container to fetch ("locate") some of its dependencies, or to run some of its processes through it.

Tight coupling

In analogy to the previous point: don't create objects using the new keyword inside a class, because you are making the class dependent of another - tight coupling. See this. The solution is the same as above: the dependency injection.

Btw, in your code you are coupling each controller to the App class as well. As mentioned, this should be avoided.

So, in the Template class you should simply have:

class Template {

    private $environment;

    public function __construct(Twig_Environment $environment) {
        $this->environment = $environment;
    }

    public function render($template, array $vars) {
        return $this->environment->render($template, $vars);
    }

}

and let the creation of the Twig environment to be performed in some other place in your code (e.g. by the DIC). Note the return statement, instead of echo: let the output of the rendered content happen on a higher level, e.g. at the bootstrap level (like index.php, or bootstrap.php) - see last code below.

Library for the main classes

Having said that, you could have a folder (like library or framework) on the project root niveau, in which all core classses such as the following could reside: Template, View, model layer constructs (like data mappers, repositories, db adapters, services, etc), Config, Session, HTTP related classes (Request, Response, Stream, Uri, etc). See this and this.

Routing

I see a routes.php file in your structure. So I am assuming that you are already familiar with the fact that the "translation" (parsing) of an URI - passed into the client (a browser) - into a route object containing the informations about a specific controller action (including the action parameters) is the responsibility of a router (most likely composed of more classes: Route, Dispatcher, Router, etc). Example of implementations: FastRoute, Aura.Router.

Front controller (request dispatching)

The task of dispaching the request, e.g. of finding - and, eventually, creating - a route object in a predefined routes collection (based on the provided URI) and calling the controller action (with the action parameters as arguments), is of the so called front controller. It will receive the router and a dispatcher as dependencies. In short, this front controller grabs a route object from the router and passes its informations to the dispatcher, which is responsible for calling the action. An example:

class FrontController {

    private $router;
    private $dispatcher;

    public function __construct(Router $router, Dispatcher $dispatcher) {
        $this->router = $router;
        $this->dispatcher = $dispatcher;
    }

    public function routeAndDispatch(ServerRequestInterface $request, ResponseInterface $response) {
        $route = $this->router->route($request->getMethod(), $request->getUri()->getPath());
        $this->dispatcher->dispatch($route, $request, $response);
        return $this;
    }

}

A good tutorial on this theme is presented in here, and the continuation here.

HTTP message abstraction (PSR-7)

Having in mind the nature of the web applications, based on request and response, you should familiarize yourself a bit with the PSR-7 recommendation. It provides an abstraction of the HTTP message - composed of a HTTP request and a HTTP response. A good standalone library is Zend-Diactoros.

Namespaces vs. file system structure (PSR-4)

Regarding the file system/namespaces structure: As per PSR-4 recommendation, a file with a class in it should have the same name as the class. Also, if you use imports (use keyword), then you don't have to use the fully qualified class name in other places of the code too. So, correct is like:

namespace App\Controllers\Frontend\Guest;

use App\App;

App::getProvider(...)->...;

Controllers and views - 1:1 relation

Please note that a view-controller relation could be 1:1. Their action methods would be then called separately (in the front controller):

// Call the controller action.
call_user_func_array([$controller, "login"], <action-params>);

// Call the view action.    
call_user_func_array([$view, "login"], <action-params>);

// Call the output method of the view and print.
echo call_user_func_array([$view, "output"]);

In this constellation both, controller and view, can share different objects - like services, or domain objects (by many called "models"), or data mappers, etc. Let's say, that a controller and a view share a domain object - for example a "User" object. That means that both receive a certain domain object as constructor argument. This object will be, of course, automatically injected by the DIC.

First separation of concerns

By doing so, a first separation of concerns takes place:

  • The controller changes the state of the domain object (e.g. the value of its properties) and no more than that. No more "presentation"-related tasks...
  • All these "presentation"-related tasks remain the duty of the view - as it should, isn't it? And because the view receives the same "User" object as argument, it has access to the state values already set/changed by the controller. In the situation here the domain object is responsible with the db interaction too - not good though. Anyway, the view puts the template instance to work, requests the domain object to query the db and to return the results, and, in the end, returns the rendered content to be presented on screen with a simple echo.

Like:

class PdoAdapter implements AdapterInterface {

    private $connection;

    public function __construct(PDO $connection) {
        $this->connection = $connection;
    }

    public function fetchColumn(string $sql, array $bindings = [], int $columnNumber = 0) {
        $statement = $this->connection->prepare($sql);
        $statement->execute($bindings);
        return $statement->fetchColumn($columnNumber);
    }

}

class LoginController {

    private $user;

    public function __construct(UserInterface $user) {
        $this->user = $user;
    }

    public function login($name, $password) {
        $this->user->setName($name);
        $this->user->setPassword($password);
    }

}

class User implements UserInterface {

    private $adapter;
    private $name;
    private $password;

    public function __construct(AdapterInterface $adapter) {
        $this->adapter = $adapter;
    }

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function getPassword() {
        return $this->password;
    }

    public function setPassword($password) {
        $this->password = $password;
    }

    public function checkLoggedIn($name, $password) {
        $sql = 'SELECT COUNT(*) FROM users WHERE name=:name AND password=:password LIMIT 1';
        $bindings = [
            ':name' => $name,
            ':password' => $password,
        ];

        return $this->adapter->fetchColumn($sql, $bindings) > 0;
    }

}

class LoginView {

    private $user;
    private $template;

    public function __construct(UserInterface $user, Template $template) {
        $this->user = $user;
        $this->template = $template;
    }

    public function login() {
        //...
    }

    public function output() {
        return $this->template->render('index.html', [
            'loggedIn' => $this->user->checkLoggedIn(
                $this->user->getName()
                , $this->user->getPassword()
            ),
        ]);
    }

}

Second separation of concerns - the MVC goal

In order to further separate the tasks, use data mappers, as intermediaries between the domain objects and the db (or the persistence layers, in general). E.g. in order to transfer data between the domain objects and the db.

In this step, the business logic, represented in and by the domain objects, become completely separated from any other app components. With this step, the actual goal of the MVC pattern is achieved: the decoupling of business logic from any other app structures/processes.

This can be seen in the following example: the User entity contains now only its properties and the methods related to them. The db functionality belongs now to the data mapper.

<?php

class PdoAdapter implements AdapterInterface {
    // ... The same ...
}

class UserMapper implements UserMapperInterface {

    private $adapter;

    public function __construct(AdapterInterface $adapter) {
        $this->adapter = $adapter;
    }

    public function checkLoggedIn($name, $password) {
        $sql = 'SELECT COUNT(*) FROM users WHERE name=:name AND password=:password LIMIT 1';
        $bindings = [
            ':name' => $name,
            ':password' => $password,
        ];

        return $this->adapter->fetchColumn($sql, $bindings) > 0;
    }

}

class LoginController {

    private $user;
    private $mapper;

    public function __construct(UserInterface $user, UserMapperInterface $mapper) {
        $this->user = $user;
        $this->mapper = $mapper;
    }

    public function login($name, $password) {
        $this->user->setName($name);
        $this->user->setPassword($password);
    }

}

class User implements UserInterface {

    private $name;
    private $password;

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function getPassword() {
        return $this->password;
    }

    public function setPassword($password) {
        $this->password = $password;
    }

}

class LoginView {

    private $user;
    private $mapper;
    private $template;

    public function __construct(UserInterface $user, UserMapperInterface $mapper, Template $template) {
        $this->user = $user;
        $this->mapper = $mapper;
        $this->template = $template;
    }

    public function login() {
        //...
    }

    public function output() {
        $loggedIn = $this->mapper->checkLoggedIn(
                $this->user->getName()
                , $this->user->getPassword()
        );

        return $this->template->render('index.html', [
                    'loggedIn' => $loggedIn
        ]);
    }

}

Further separations/optimizations

  • (Optional) Use repositories to intermediate between the domain objects and the data mappers.
  • Use services to interact with the domain objects and the data mappers/repositories.
  • Share the services between the controllers and the views.

This great answer describes this part in detail.

And as last thing: all these dependencies in the examples are managed by the dependency injection container.


How to wire all together (steps):

• Define all "config" definitions, which will be registered into the dic. I speak about configuration values only, which will be further read by other "general" definitions of the dic, in order to create objects. The "config" definitions will probably reside in configuration files (e.g. definition files). So, for example, the definition file for the twig components could look like this:

config/configs/twig.php:

<?php

return [
    'twig' => [
        'options' => [
            'debug' => TRUE,
            'charset' => 'UTF-8',
            'base_template_class' => 'Twig_Template',
            'strict_variables' => FALSE,
            'autoescape' => 'html',
            'cache' => __DIR__ . '/../../storage/cache/twig',
            'auto_reload' => TRUE,
            'optimizations' => -1,
        ],
        'extensions' => [/* Indexed array with Twig_Extension_xxx instances */
            new Twig_Extension_Debug(),
        ],
    ],
];

• Define all "general" definitions, which will be registered into the dic and are used to create objects. But I don't speak here about the "specific" definitions, used to create specific objects like controllers, views, domain ojects, data mappers, etc. The "general" definitions will probably reside in one file. For example:

config/generals.php:

<?php

// Here come the imports...

return [
    'router' => function (ContainerInterface $c) {
        $dispatcher = 'Here create the route dispatcher...';
        return new Router($dispatcher);
    },
    'request' => factory([ServerRequestFactory::class, 'build']), /* Built with defaults */
    'response' => function (ContainerInterface $c) {
        return new Response(new Stream() /* defaults */);
    },
    'twigEnvironment' => function (ContainerInterface $c) {
        $loader = new Twig_Loader_Filesystem();
        $options = $c->get('twig')['options'];
        $environment = new Twig_Environment($loader, $options);

        $extensions = $c->get('twig')['extensions'];
        foreach ($extensions as $extension) {
            $environment->addExtension($extension);
        }

        return $environment;
    },
];

• Define all "specific" definitions, which will be registered into the dic and are used to create objects. I speak here about the definitions used to create controllers, views, domain ojects, data mappers, etc, but only for the dependencies type-hinted with interfaces or not type-hinted at all ("skalar" parameters). These "specific" definitions will probably reside in one file:

config/specifics.php:

<?php

use function DI\get;
use function DI\object;
use Mymvc\Models\User\User;
use Mymvc\Views\Login\LoginView;
use Mymvc\Models\User\UserMapper;
use Mymvc\Controllers\Login\LoginController;

return [
    LoginController::class => object()
            ->constructorParameter('user', get(User::class))
            ->constructorParameter('mapper', get(UserMapper::class)),
    LoginView::class => object()
            ->constructorParameter('user', get(User::class))
            ->constructorParameter('mapper', get(UserMapper::class)),
];

These "specific" definitions are based on the following LoginController:

<?php

namespace Mymvc\Controllers\Login;

use Mymvc\Models\User\UserInterface;
use Mymvc\Models\User\UserMapperInterface;

class LoginController {
    public function __construct(UserInterface $user, UserMapperInterface $mapper) {
        //...
    }
}

and on the following LoginView:

<?php

namespace Mymvc\Views\Login;

use Mylib\Presentation\Template;
use Mymvc\Models\User\UserInterface;
use Mymvc\Models\User\UserMapperInterface;

class LoginView {

    public function __construct(UserInterface $user, UserMapperInterface $mapper, Template $template) {
        //...
    }

}

Important: The Template dependency of the LoginView must not be defined in the "config/specifics.php" file, because for all concrete type-hints the DIC automatically creates instances! In this so-called autowiring process lies the real power of any DIC.

Note that get & object in "config/specifics.php" are functions of the DIC.

• Define all routes, which will be registered into the router. They could reside in config/routes.php

• In index.php only include the bootstrap file. So, index.php contains only one line:

<?php require_once '../bootstrap.php'; ?>

From here on the work is made in bootstrap.php, which resides directly in the project root.

• Load Composer autoloader.

• Create an instance of the DIC builder.

• Register all previously defined definitions into the DIC.

• Compile the container, e.g. the DIC.

• Get the router from the DIC.

• Register all previously defined routes into the router.

• Read the uri from the browser.

• Pass it to the router and call the dispatch method of the router. The router compares the uri with each registered route and, if it finds a match, it will return an array with the informations contained in the registered route ("route infos" array).

• The route infos are: the controller name, the action name and the action parameters list.

• Get the request object from the DIC by reading the 'request' entry from it and get the response object from the DIC by reading the 'response' entry from it. The generated response object will be probably used along the way before the controller action is called. For example, if you want to create a controller instance, but no controller class exists, then you'll use the response object to output an error message or a customized error page.

• Save the route infos into the request object as "attributes", e.g. with the withAttribute() method of the PSR-7 recommendation. From hear on read them only from the request object.

• Register the request object into the DIC by setting an entry ServerRequestInterface::class into it with the value of the request object. This way, because of autowiring, each time a dependency ServerRequestInterface is needed everywhere the assigned request object containing the route infos will be automatically injected.

$container->set(ServerRequestInterface::class, $request);

• If you don't use the response object for some operations before calling controller/view action anymore, then you can already register it into the DIC by setting an entry ResponseInterface::class. This way, because of autowiring, each time a dependency ResponseInterface is needed everywhere the assigned response will be automatically injected.

$container->set(ResponseInterface::class, $response);

• If an object of a certain type don't need to perform operations before the controller/view action is called, then you can register it as entry of DIC from the beginning. Otherwise, similar with request/response objects, create an instance of that type, use it, then register it afterwords. For example, a session object is needed to perform some session functions. After these ops are finished, a 'Session::class` entry can be registered in DIC.

• Based on the route infos and on the paths/namespaces registered as configs (e.g. "config" definitions in DIC) build the fully qualified class name (FQN) of the controller and of the view.

• Call the controller action. If not, no problem: the view action of the view is called. Make also proper validations (file/class exist, method exists). But use the call() method of the container (e.g. DIC), so that the automatic injection takes place!

• Here is the most awaited moment: create a Template object (by using the configs/paths/namespaces registered in DIC inclusive the 'twigEnvironment' entry) and register it into DIC. For example:

In config/configs/app.php:

<?php

return [
    'paths' => [
        // This folder contains the templates and the layouts of the application, used by your view classes if no "specific" layouts/templates are used.
        'appTemplates' => __DIR__ . '/../../resources/templates/app'
        // This folder contains the templates and the layouts loaded/rendered by the specific view classes (LoginView, HomeView, AboutUsVIew, etc).
        'customTemplates' => __DIR__ . '/../../resources/templates/app'
    ],
];

And now in bootsptrap.php:

$appTemplatesPath = $container->get('appTemplates');
$customTemplatesPath = $container->get('customTemplates');
$twigEnvironment = $container->get('twigEnvironment');

$template = new Template(
    $twigEnvironment
    , $appTemplatesPath
    , $customTemplatesPath
);

$container->set(Template::class, $template);

• Call the view action if exists. If not, no problem: the 'output' method of the view is called. Make also proper validations (file/class exist, method exists). And use the call() method of the container (e.g. DIC), so that the automatic injection takes place!

• Call the 'output' method of the view and print the result with echo. If none exists then throw an exception: the program is broken. Make also all proper validations (file/class exist, method exists). And use the call() method of the container (e.g. DIC), so that the automatic injection takes place!

• The end...

Good luck.

Original Thread

By anonymous    2018-03-05

The question is, do you need to pass a Job instance - as dependency - to the Person object, if it's only about the job name - like in the following context? I would say not really:

class Person {

    /**
     * Person name.
     *
     * @var string
     */
    private $name;

    /**
     * Job name.
     *
     * @var string
     */
    private $job;

    /**
     * Person's age.
     *
     * @var int
     */
    private $age;

    /**
     * Person's place of birth.
     *
     * @var string
     */
    private $birthPlace;

    /**
     * Job name.
     *
     * @param string $name Person name.
     * @param string $job Job name.
     * @param int $age Person's age.
     * @param string $birthPlace Person's place of birth.
     */
    public function __construct(string $name, string $job, int age, string $birthPlace) {
        $this->name = $name;
        $this->job = $job;
        $this->age = $age;
        $this->birthPlace = $birthPlace;
    }

    /**
     * Get person's details.
     * 
     * @return string
     */
    public function getDetails() {
        return $this->name . ', ' . $this->job . ', ' . $this->age . ', ' . $this->birthPlace;
    }

}

use Person;

$person = new Person('TLG', 'programmer', 28, 'Paris');

echo $person->getDetails();

But what if more specific job details are to be assigned to a person? Then a Job instance can be used:

/*
 * Job.
 */

class Job {

    /**
     * Job name.
     *
     * @var string
     */
    private $name;

    /**
     * Job location.
     *
     * @var string
     */
    private $location;

    /**
     * 
     * @param string $name Job name.
     * @param string $location Job location.
     */
    public function __construct(string $name, string $location) {
        $this->name = $name;
        $this->location = $location;
    }

    /**
     * Get the job name.
     * 
     * @return string
     */
    public function getName() {
        return $this->name;
    }

    /**
     * Get the job location.
     * 
     * @return string
     */
    public function getLocation() {
        return $this->location;
    }

}


/*
 * Person.
 */

use Job;

class Person {

    /**
     * Person name.
     *
     * @var string
     */
    private $name;

    /**
     * Job instance.
     *
     * @var Job
     */
    private $job;

    /**
     * 
     * @param string $name Person name.
     * @param Job $job Job instance.
     */
    public function __construct(string $name, Job $job) {
        $this->name = $name;
        $this->job = $job;
    }

    /**
     * Get person's details.
     * 
     * @return string
     */
    public function getDetails() {
        return $this->name . ', ' . $this->job->getName() . ' in ' . $this->job->getLocation();
    }

}


/*
 * The call.
 */

use Job;
use Person;

$job = new Job('Programmer', 'London');
$person = new Person('John', $job);

echo $person->getDetails();

Notes:

  • You should make all properties private. For the ones needed to be accessible from outside create public getters/setters, in order to ensure encapsulation.
  • You should use namespaces. In this case, since both classes are defined in the global namespace, you don't need to import any classes, e.g. use the statements beginning with the use keyword. Though, in other situations, where defining top-level namespaces and subnamespaces is needed, then you should definitely make use of import statements. They will give you a very elegant way of manipulating class names and increase the readability of your class codes. See PSR-1: Basic Coding Standard, PSR-2: Coding Style Guide, PSR-4: Autoloader.

Now, what if a person can have multiple jobs? Then you could use a JobCollection:

 /*
 * Job.
 */

class Job {

    // Same as above...

}


/*
 * Job collection.
 */

use Job;

class JobCollection {

    /**
     * Jobs list.
     *
     * @var Job[]
     */
    private $jobs = [];

    /**
     * Add a job.
     * 
     * @return $this
     */
    public function add(Job $job) {
        $this->jobs[] = $job;
        return $this;
    }

    /**
     * Get all jobs.
     * 
     * @return Job[]
     */
    public function all() {
        return $this->jobs;
    }

}


/*
 * Person.
 */

use JobCollection;

class Person {

    /**
     * Person name.
     *
     * @var string
     */
    private $name;

    /**
     * Job collection.
     *
     * @var JobCollection
     */
    private $jobs;

    /**
     * 
     * @param string $name Person name.
     * @param JobCollection $jobs Job collection.
     */
    public function __construct(string $name, JobCollection $jobs) {
        $this->name = $name;
        $this->jobs = $jobs;
    }

    /**
     * Get the person name.
     * 
     * @return string
     */
    public function getName() {
        return $this->name;
    }

    /**
     * Get the person's jobs.
     * 
     * @return Job[]
     */
    public function getJobs() {
        return $this->jobs->all();
    }

    /**
     * Get person's details.
     * 
     * @return string
     */
    public function getDetails() {
        $result = $this->getName() . '<br/>';

        foreach ($this->jobs->all() as $job) {
            $result .= $job->getName() . ' in ' . $job->getLocation() . '<br/>';
        }

        return $result;
    }

}


/*
 * The call.
 */

use Job;
use Person;
use JobCollection;

// Create some jobs.
$job1 = new Job('Programmer', 'London');
$job2 = new Job('Bartender', 'Paris');

// Create the job collection and add the jobs to it.
$jobs = new JobCollection();
$jobs
        ->add($job1)
        ->add($job2)
;

// Create the person.
$person = new Person('John', $jobs);

echo $person->getDetails();

The Law of Demeter, as greatly presented in The Clean Code Talks - Don't Look For Things!, specifies that you should only inject dependencies which are directly used by a class. E.g. you shouldn't pass dependencies having the role of intermediaries, e.g. which are only used to create other objects whos methods you need to call.

In the earlier version of my answer I gave you the impression that it's false to use a Job instance in a Person object in order to assign the job name. It is correct to use a Job instance. By using it you are not breaking the LoD per se, but only the nuance of it, that you don't really need a Job instance in order to assign a job name to a Person object (as in my first example) if the job doesn't imply a more specifical case (as in the second example and in your good question in the comment).

Original Thread

By anonymous    2018-03-18

Make the database property protected.

Also: $this->$database is wrong. Correct is $this->database.

Be aware that your class design is based on the service locator antipattern. E.g. you are passing the whole container to your controllers in order to get the database object from it. Don't do this! Inject only the resources that a class needs. E.g. your controller should receive only the database instance as dependency. Take a look at this, this, this and, especially, this.

You don't actually want to inject the database instance either. You should inject it into proper data mappers. And the data mappers should be injected into the controllers. In principle, the process of accessing data from a persistence layer is the responsibility of more MVC components. Read this and this. And this serie for code examples involving domain objects, database adapters, data mappers, repositories and services: Part 1, Part 2, Part 3 and Part 4.

A note: in Slim you can use the Eloquent ORM. See this.

Suggestion: You should learn OOP before starting (using) an MVC and familiarize yourself with the SOLID principles too.

class Controller {

    private $container;
    protected $database;

    public function __construct($container) {
        $this->container = $container;
        $this->database = $this->container->get('db');

        $lieux = $this->database->query('SELECT * FROM Lieu');
        var_dump($lieux);
    }

    public function render(ResponseInterface $response, $file) {
        $this->container->view->render($response, $file);
    }

}

class PagesController extends Controller {

    public function getLieu(RequestInterface $request, ResponseInterface $response) {
        $lieux = $this->database->query('SELECT * FROM Lieu');
        var_dump($lieux);

        $this->render($response, 'pages/lieu.twig');
    }

}

Original Thread

By anonymous    2018-03-26

Misko Hevery has said before (I believe it was in Clean Code Talks: Don't Look for Things but I may be wrong) that he doesn't know how to effectively unit test main methods, so his solution is to make them so simple that you can prove logically that they work if you assume the correctness of the (unit-tested) code that they call.

For example, if you have a discrete, tested unit for parsing command line arguments; a library that does the actual work; and a discrete, tested unit for rendering the completed work into output, then a main method that calls all three of those in sequence is assuredly going to work.

With that architecture, you can basically get by with just one big system test that is expected to produce something other than the "default" output and it'll either crash (because you wired it up improperly) or work (because it's wired up properly and all of the individual parts work).


At this point, I'm dropping all pretense of knowing what I'm talking about. There is almost assuredly a better way to do this, but frankly you could just write a shell script:

python -m package args
test $? -eq [expected exit code]

That will exit with error iff your program outputs incorrectly, which TravisCI or similar will regard as build failing.

Original Thread

Submit Your Video

If you have some great dev videos to share, please fill out this form.