22/10/2019, 16:24

Tự xây dựng một framework php - part3

=> xử lí lỗi khi có lỗi xảy ra trong project , hiển thị chi tiết lỗi, trace, detail request header.. giúp chúng ta debug nhanh chóng và dễ dàng cài đặt composer require filp/whoops thêm vào file bootstrap.php $environment = 'dev' ; /** * Register the error handler */ $whoops ...

=> xử lí lỗi khi có lỗi xảy ra trong project , hiển thị chi tiết lỗi, trace, detail request header.. giúp chúng ta debug nhanh chóng và dễ dàng

cài đặt

composer require filp/whoops

thêm vào file bootstrap.php

$environment = 'dev';

/**
* Register the error handler
*/
$whoops = new WhoopsRun;
if ($environment !== 'prod') {
    $whoops->pushHandler(new WhoopsHandlerPrettyPageHandler);
} else {
    $whoops->pushHandler(function($e){
        echo 'internal server error';
    });
}
$whoops->register();

ở đây mình tạo biến environment để check xem nếu đang ở chế độ development thì hiển thị lỗi cho dev dễ fix

nếu là môi trường production chỉ nên hiển thị trang thông báo lỗi chung chung để phía user không thấy được lỗi.. đề phòng "hacker" tấn công hệ thống thông qua các lỗi hiển thị

ví dụ: trong file TestController.php ta thêm dòng code 4/0; để bắn ra lỗi

public function bird()
    {
        4/0;
        echo 'Trên cành cây';
    }

Khi chưa cài thư viện handle lỗi

Sau khi cài

Đấy giao diện rất là trực quan, nhìn vào là biết ngay lỗi ở đâu ????

bài này mình ko nói về khái niệm này nữa

Chúng ta sẽ implement package này Auryn document của nó ở đây Docs

composer require rdlowrey/auryn

tạo thêm file Dependencies.php trong thư mục app

<?php
$injector = new AurynInjector;


$injector->define('SymfonyComponentHttpFoundationRequest', [
    ':query' => $_GET,
    ':request' => $_POST,
    ':attributes' => [],
    ':cookies' => $_COOKIE,
    ':files' => $_FILES,
    ':server' => $_SERVER,
    ':content' => null,
]);

$injector->share('SymfonyComponentHttpFoundationResponse');

$injector->alias('AppContractsBirdServiceInterface', 'AppServicesBirdService');

return $injector;

Các bạn đọc thêm docs để hiểu thêm về alias, share và define

define hiểu đơn giản như set parameter, or bind class

share: dùng chung object kiểu như Singleton

alias: kiểu như là interfaceA này sẽ đc khởi tạo bởi servicesA nào đấy

ok.. đọc lại đoạn code trên cũng hiểu phần nào chức năng của nó rồi nhỉ :v

next:

sửa lại code ở file appoostrap.php ở những part trước để implement cái mới nà:

thay

$request = Request::createFromGlobals();

$response = new Response();

bằng:

$request = $injector->make('SymfonyComponentHttpFoundationRequest');
$response = $injector->make('SymfonyComponentHttpFoundationResponse');

thay

$class = new $className;
$class->$method($vars);

bằng

$class = $injector->make($className);
$class->$method($vars);

file appoostrap.php sau khi sửa sẽ như sau

<?php

use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;

$environment = 'dev';

/**
* Register the error handler
*/
$whoops = new WhoopsRun;
if ($environment !== 'prod') {
    $whoops->pushHandler(new WhoopsHandlerPrettyPageHandler);
} else {
    $whoops->pushHandler(function($e){
        echo 'internal server error';
    });
}
$whoops->register();


$injector = include('Dependencies.php');

$request = $injector->make('SymfonyComponentHttpFoundationRequest');
$response = $injector->make('SymfonyComponentHttpFoundationResponse');

$dispatcher = FastRoutesimpleDispatcher(function (FastRouteRouteCollector $router) {
    include '../routes/web.php';
});

$routeInfo = $dispatcher->dispatch($request->getMethod(), $request->getPathInfo());

switch ($routeInfo[0]) {
    case FastRouteDispatcher::NOT_FOUND:
        $response->setContent('404 - Page not found');
        $response->setStatusCode(404);
        break;
    case FastRouteDispatcher::METHOD_NOT_ALLOWED:
        $response->setContent('405 - Method not allowed');
        $response->setStatusCode(405);
        break;
    case FastRouteDispatcher::FOUND:
        $response->setStatusCode(200);
        if(gettype($routeInfo[1]) === 'string'){
            $rInfo = explode('@', $routeInfo[1]);

            $className = $rInfo[0];
            $method = $rInfo[1];
            $vars = $routeInfo[2];

            $class = $injector->make($className);
            $class->$method($vars);
        } else {
            $handler = $routeInfo[1];
            $vars = $routeInfo[2];
            call_user_func($handler, $vars);
        }

        break;
}

$response->prepare($request);
$response->send();

Tiếp theo tạo appContractsBirdServiceInterface.php

<?php

namespace AppContracts;

interface BirdServiceInterface
{
    /**
     * @return string
     */
    public function fly();
}

... và AppServicesBirdService.php

<?php

namespace AppServices;

use AppContractsBirdServiceInterface;

class BirdService implements BirdServiceInterface
{
    public function fly()
    {
        return 'fly fly fly';
    }
}

sửa file appControllersTestController.php;

<?php

namespace AppControllers;

use AppContractsBirdServiceInterface;
use SymfonyComponentHttpFoundationResponse;

class TestController
{
    public function __construct(Response $response, BirdServiceInterface $birdService) {
        $this->birdService = $birdService;
        $this->response = $response;
    }

    public function bird()
    {
        $rs = $this->birdService->fly();
        $this->response->setContent($rs);
    }
}

nhờ cấu hình ở trên file appDependencies.php

$injector->alias('AppContractsBirdServiceInterface', 'AppServicesBirdService');

sẽ tìm BirdServiceInterface và khởi tạo bằng BirdService

kết quả:

part 4 to continue...

0