フレームワークのない最新のPHP


あなたには難しい仕事があります。 次回新しいプロジェクトを開始するときは、PHPフレームワークなしで実行してみてください。 フレームワークの欠陥をリストするつもりはありません。これは、 他人の開発が拒否されるという症状の表れではありません。このガイドでは、いくつかのフレームワークの開発者が作成したパッケージを使用します。 私はこの分野の革新を完全に尊重しています。


しかし、この記事はそれらについてのものではありません。 彼女はあなたのことです。 開発者としてより良くなる機会について。


おそらく、フレームワークを放棄することの主な利点は、すべてが内部でどのように機能するかを知ることです。 あなたはあなたを気にするフレームワークに依存せずに何が起こるかを見るでしょう。


次の仕事では、フレームワークなしで新しいプロジェクトの立ち上げを楽しむことはできないでしょう。 ビジネスに不可欠な多くの重要なPHPタスクには、既存のアプリケーションの使用が含まれます。 このアプリケーションが、LaravelやSymfonyなどの最新のフレームワーク、CodeIgniterやFuelPHPなどの古いプラットフォームのいずれかで構築されているか、「インクルード指向アーキテクチャ」を備えた気のめいるように普及しているレガシーPHPアプリケーションかどうかは関係ありません。 、その後将来のPHPプロジェクトの準備が整います。


一部のシステムは 、HTTP要求の解釈とルーティング、HTTP応答の送信、依存関係の管理を強制されるためフレームワークなしで作成しようとしました。 標準の欠如は、少なくともこれらのフレームワークコンポーネントが密接に相互リンクされることを避けられませんでした。 したがって、フレームワークなしでプロジェクトの開発を開始した場合、最終的には独自のフレームワークを作成することになります。


しかし、今日では、スタートアップと相互互換性の分野でのPHP-FIGの努力のおかげで、フレームワークなしで、途中で作成することなく開発できます。 多数の開発者が作成した、相互に互換性のある多くの素晴らしいパッケージがあります。 そして、それらを単一のシステムに組み立てることは、あなたが考えるよりもはるかに簡単です!


PHPはどのように機能しますか?


まず、PHPアプリケーションが外界とどのように相互作用するかを理解することが重要です。


PHPは、要求/応答サイクルでサーバーアプリケーションを実行します。 ブラウザー、コマンドライン、またはREST APIからのアプリケーションとのすべてのやり取りは、リクエストとして処理されます。 要求を受信すると、アプリケーションは要求をロードして処理し、クライアントに送り返す応答を生成して、アプリケーションを閉じます。 そして、これはあらゆる治療で起こります。


クエリコントローラー


この知識を武器に、フロントコントローラーから始めましょう。 これは、アプリケーションへのすべてのリクエストを処理するPHPファイルです。 つまり、これはリクエストが該当する最初のPHPファイルであり、(実際には)アプリケーションの応答が通過する最後のPHPファイルです。


PHP組み込みWebサーバーが提供する古典的なHello、world !の例を使用して、すべてが正しく構成されているかどうかを確認してください。 まだ行っていない場合は、PHP 7.1以降が環境にインストールされていることを確認してください。


, public, — index.php :


<?php
declare(strict_types=1);

echo 'Hello, world!';

, — PHP- , — (type hinting) , .


( Terminal MacOS) PHP -.


php -S localhost:8080 -t public/

http://localhost:8080/. Hello, world! ?


. !



PHP, , , include require PHP-. , , . .


— . , , - , PHP , , . PHP 5, PSR-0 ( , PSR-4).


, Composer , , .


, Composer. .


composer init

composer.json. autoload, , ( , ).


{
    "name": "kevinsmith/no-framework",
    "description": "An example of a modern PHP application bootstrapped without a framework.",
    "type": "project",
    "require": {},
    "autoload": {
        "psr-4": {
            "ExampleApp\\": "src/"
        }
    }
}

Composer, ( ) .


composer install

public/index.php . include, .


<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/vendor/autoload.php';

echo 'Hello, world!';

, . , . Hello, world! , , .


src HelloWorld.php :


<?php
declare(strict_types=1);

namespace ExampleApp;

class HelloWorld
{
    public function announce(): void
    {
        echo 'Hello, autoloaded world!';
    }
}

public/index.php echo announce HelloWorld.


// ...

require_once dirname(__DIR__) . '/vendor/autoload.php';

$helloWorld = new \ExampleApp\HelloWorld();
$helloWorld->announce();

!


?


— , , , - .


, . . , .


class AwesomeClass
{
    public function doSomethingAwesome()
    {
        $dbConnection = return new \PDO(
            "{$_ENV['type']}:host={$_ENV['host']};dbname={$_ENV['name']}",
            $_ENV['user'],
            $_ENV['pass']
        );

        // Make magic happen with $dbConnection
    }
}

. , . . , . .


, . , PDO .


class AwesomeClass
{
    private $dbConnection;

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

    public function doSomethingAwesome()
    {        
        // Make magic happen with $this->dbConnection
    }
}

, . , , . , .


— , . , .


DI- PHP PHP-DI. ( , , - .)



Composer, PHP-DI . :


composer require php-di/php-di

public/index.php .


// ...

require_once dirname(__DIR__) . '/vendor/autoload.php';

$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->useAutowiring(false);
$containerBuilder->useAnnotations(false);
$containerBuilder->addDefinitions([
    \ExampleApp\HelloWorld::class => \DI\create(\ExampleApp\HelloWorld::class)
]);

$container = $containerBuilder->build();

$helloWorld = $container->get(\ExampleApp\HelloWorld::class);
$helloWorld->announce();

. , .


, ( ) HelloWorld.


: , , . , - , . . , , .


, , .


<?php
declare(strict_types=1);

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

require_once dirname(__DIR__) . '/vendor/autoload.php';

$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(false);
$containerBuilder->useAnnotations(false);
$containerBuilder->addDefinitions([
    HelloWorld::class => create(HelloWorld::class)
]);

$container = $containerBuilder->build();

$helloWorld = $container->get(HelloWorld::class);
$helloWorld->announce();

, , .


, , , . .


https://kevinsmith.io/modern-php-without-a-framework-middleware


Middleware


, , , middleware — , , , - . , - .


, . , , .


:



— ? . middleware / , .


: .



, , (, URI /products/purple-dress/medium ProductDetails::class purple-dress medium).


FastRoute , PSR-15.


middleware


- , .


PSR-15 — , middleware ( « »), . , PSR-15, middleware.


Relay.


composer require relay/relay:2.x@dev

PSR-15 , HTTP-, PSR-7, Zend Diactoros.


composer require zendframework/zend-diactoros

Relay .


// ...

use DI\ContainerBuilder;
use ExampleApp\HelloWorld;
use Relay\Relay;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;

// ...

$container = $containerBuilder->build();

$middlewareQueue = [];

$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());

16 ServerRequestFactory::fromGlobals() , Relay. .


FastRoute (FastRoute , , , ).


composer require middlewares/fast-route middlewares/request-handler

Hello, world!.. /hello, , URI.


// ...

use DI\ContainerBuilder;
use ExampleApp\HelloWorld;
use FastRoute\RouteCollector;
use Middlewares\FastRoute;
use Middlewares\RequestHandler;
use Relay\Relay;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
use function FastRoute\simpleDispatcher;

// ...

$container = $containerBuilder->build();

$routes = simpleDispatcher(function (RouteCollector $r) {
    $r->get('/hello', HelloWorld::class);
});

$middlewareQueue[] = new FastRoute($routes);
$middlewareQueue[] = new RequestHandler();

$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());

, HelloWorld, , .


// ...

class HelloWorld
{
    public function __invoke(): void
    {
        echo 'Hello, autoloaded world!';
        exit;
    }
}

exit; __invoke(). , .


http://localhost:8080/hello !


,


, DI-, , . .


?


, — — HelloWorld ?


, .


// ...

class HelloWorld
{
    private $foo;

    public function __construct(string $foo)
    {
        $this->foo = $foo;
    }

    public function __invoke(): void
    {
        echo "Hello, {$this->foo} world!";
        exit;
    }
}

, ...


.


ArgumentCountError.


, HelloWorld , . .


RequestHandler .


// ...

use Zend\Diactoros\ServerRequestFactory;
use function DI\create;
use function DI\get;
use function FastRoute\simpleDispatcher;

// ...

$containerBuilder->addDefinitions([
    HelloWorld::class => create(HelloWorld::class)
        ->constructor(get('Foo')),
    'Foo' => 'bar'
]);

$container = $containerBuilder->build();

// ...

$middlewareQueue[] = new FastRoute($routes);
$middlewareQueue[] = new RequestHandler($container);

$requestHandler = new Relay($middlewareQueue);
$requestHandler->handle(ServerRequestFactory::fromGlobals());

! Hello, bar world!.



, exit HelloWorld?


, , . HelloWorld — , — , , , HelloWorld.


, , ( ) . Request PSR-7 HTTP-, : Response. , HTTP- , PSR-7 Request Response.


HelloWorld Response.


// ...

namespace ExampleApp;

use Psr\Http\Message\ResponseInterface;

class HelloWorld
{
    private $foo;

    private $response;

    public function __construct(
        string $foo,
        ResponseInterface $response
    ) {
        $this->foo = $foo;
        $this->response = $response;
    }

    public function __invoke(): ResponseInterface
    {
        $response = $this->response->withHeader('Content-Type', 'text/html');
        $response->getBody()
            ->write("<html><head></head><body>Hello, {$this->foo} world!</body></html>");

        return $response;
    }
}

, HelloWorld Response.


// ...

use Middlewares\RequestHandler;
use Relay\Relay;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;

// ...

$containerBuilder->addDefinitions([
    HelloWorld::class => create(HelloWorld::class)
        ->constructor(get('Foo'), get('Response')),
    'Foo' => 'bar',
    'Response' => function() {
        return new Response();
    },
]);

$container = $containerBuilder->build();

// ...

, . Response, … ?


.


: . - (Apache, nginx . .) , . Response , API.


! Zend Diactoros, , PSR-7.


. , . Zend.


public/index.php Response .


// ...

use Relay\Relay;
use Zend\Diactoros\Response;
use Zend\Diactoros\Response\SapiEmitter;
use Zend\Diactoros\ServerRequestFactory;
use function DI\create;

// ...

$requestHandler = new Relay($middlewareQueue);
$response = $requestHandler->handle(ServerRequestFactory::fromGlobals());

$emitter = new SapiEmitter();
return $emitter->emit($response);

— ! .


15 / -.



44 , , , bootstrap PHP-. PSR-4, PSR-7, PSR-11 PSR-15, HTTP-, DI-, middleware .


, , . , .


, .


, Aura, The League of Extraordinary Packages, Symfony, Zend Framework, Paragon Initiative PSR-15 middlleware.


production, , , , . EmitterStack «» .



Source: https://habr.com/ru/post/J352122/


All Articles