minte9
LearnRemember



PROJECT SETUP

Setup the project and start built-in php server
 
mkdir /var/www/php/noframework
cd /var/www/php/noframework
mkdir public

echo "<?= 'Hello World' ?>" > public/index.php

php -S localhost:8080 -t /var/www/php/noframework

        // http://localhost:8080/public
        // Hello World

// Ctrl+C (stop the server)
// Failed to listen on localhost:8080 (reason: Address already in use)
// killall -9 php    # stop php server
Initialize Composer for the project and add src/ to autoload. Composer install will generate autoload files and will bring in any dependencies.
 
composer init
 
// Add ExampleApp namespace to composer.json

{
    "name": "vendor/minte9",
    "type": "project",
    "require": {},
    "autoload": {
        "psr-4": {
            ExampleApp\\": "src/"
        }
    }
}
 
// install composer

mkdir src/
composer install
 
// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'ExampleApp\\' => array($baseDir . '/src'),
);
 
// /public/index.php

declare(strict_types=1);

use ExampleApp\HelloWorld;

require_once __DIR__.'/../vendor/autoload.php';

$obj = new HelloWorld();
$obj->test();
 
// /src/HelloWorld.php

declare(strict_types=1);

namespace ExampleApp;

class HelloWorld
{
    public function test() : void
    {
        echo "Hello World - Composer autoload";
    }
}
 
// http://localhost:8080/public
// Hello World - Composer autoload

DEPENDENCY INJECTION

As an example, the UserManager takes the Mailer as a constructor parameter. This is dependency injection!
 
declare(strict_types=1);

class Mailer 
{

}

class UserManager
{
    private $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }
}

$mailer = new Mailer();
$userManager = new UserManager($mailer); // Look Here
If we add the pdo connection inside the method, to the class is coupled to both app and db. This is messy!
 
class HelloWorld
{
    ...

    public doSomething()
    {
        // $dbConnection = new \PDO();
    }
}
Add PDO as a dependency to the HelloWorld Class. This lot cleaner, easier to understand and unit test.
 
// public/index.php

declare(strict_types=1);

use ExampleApp\HelloWorld;

require_once __DIR__.'/../vendor/autoload.php';

$dsn = "mysql:host=localhost;dbname=sys;charset=utf8mb4;port=3306";
$pdo = new PDO($dsn, "admin", "password");

$obj = new HelloWorld($pdo);
$obj->test();
 
// /src/HelloWorld.php

declare(strict_types=1);

namespace ExampleApp;

class HelloWorld
{
    private $dbConnection;

    public function __construct(\PDO $dbConnection)
    {
        $this->db = $dbConnection;
    }

    public function test()
    {
        echo "Hello World - autoload & PDO <br>";

        $stmt = $this->db->query("SELECT * FROM sys_config");
        while($row = $stmt->fetch()) {
            var_dump($row);
        }
    }
}

CONTAINER

A dependency injection container wraps around your entire application. It helps a lot as your application grows and became more complex. One of the most popular DI container is PHP-DI.
 
composer require php-di/php-di
 
// /public/index.php

declare(strict_types=1);

use ExampleApp\HelloWorld;
use DI\ContainerBuilder;
use function DI\create;
use function DI\get;

require_once __DIR__.'/../vendor/autoload.php';

$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(false);
$containerBuilder->useAnnotations(false);
$containerBuilder->addDefinitions([
    HelloWorld::class => function() {    // Look Here
        $dsn = "mysql:host=localhost;dbname=sys;charset=utf8mb4;port=3306";
        $pdo = new PDO($dsn, "admin", "password");
        return new HelloWorld($pdo);
    }
]);
$container = $containerBuilder->build();

$obj = $container->get(HelloWorld::class);
$obj->test(); // Hello World - autoloaded & PDO & DI
 
// /src/HelloWorld.php

declare(strict_types=1);

namespace ExampleApp;

class HelloWorld
{
    private $db;
    
    public function __construct(\PDO $pdo)
    {
        $this->db = $pdo;
    }

    public function test() : void
    {
        echo "Hello World - autoloaded & PDO & DI  <br>";

        $stmt = $this->db->query("SELECT * FROM sys_config");
        $row = $stmt->fetch();
        echo $row['variable']; // diagnostics.include_raw
    }
}
This looks like a lot of extra fuss for what we already did. The container will prove usefull when we add other tools to our application.


  Last update: 234 days ago