4

0-how.md · 学而实习之

 1 year ago
source link: https://wxyclark.github.io/Work/IT/PHP/Framework/Laravel/0-how.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

0-how.md · 学而实习之

  • public/index.php Kernel 接收 Requeset ,返回 Response
  • BeforeMiddleWare + Route + AfterMiddleWare, 前置中间件:检查请求,处理参数; Route 路由转发; 后置中间件:处理数据,后续动作
  • Controller + Action, 参数校验,调用service,返回
  • Request 定义入参、校验逻辑、错误信息
  • Service 处理业务(事务),调用 Repository,格式化数据,触发事件监听
  • Repository 处理 SQL增删改查, 建议 1个Repository注入多个Model,处理相关数据(如:父表-子表,数据表-日志表)
  • Model定义映射表

入口文件 ./public/index.php

# composer自动加载
require __DIR__.'/../vendor/autoload.php';

# 获取laravel核心的Ioc容器
$app = require_once __DIR__.'/../bootstrap/app.php';

# "make"出Http请求的内核
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

# laravel里面所有功能服务的注册加载,乃至Http请求的构造
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

# 发送请求
$response->send();

# 执行,返回
$kernel->terminate($request, $response);

Composer自动加载

  • 类的自动加载(autoload)机制 解决手动 require/include 造成的遗漏、包含不必要文件的问题。
  • Lazy loading (延迟加载) :在使用类时才自动包含类文件,而不是一开始就将所有的类文件
  • PHP 自动加载函数 __autoload()
bool  spl_autoload_register ( [callback $autoload_function] )    
接受两个参数:一个是添加到自动加载栈的函数,另外一个是加载器不能找到这个类时是否抛出异常的标志。
第一个参数是可选的,并且默认指向spl_autoload()函数,
这个函数会自动在路径中查找具有小写类名和.php扩展或者.ini扩展名,
或者任何注册到spl_autoload_extensions()函数中的其它扩展名的文件。

如果你所在的代码位置访问不了 $app 变量,可以使用辅助函数resolve:

$api = resolve('HelpSpot\API');

IOC容器

Laravel 服务容器是一个用于管理类依赖和执行依赖注入的强大工具。

  • 服务容器就是工厂模式的升级版,工厂解耦了对象和外部资源之间的关系,但是和外部资源之间存在在耦和
  • 服务容器在为对象创建了外部资源的同时,又与外部资源没有任何关系,这个就是 Ioc 容器
  • 只要不是由内部生产(比如初始化、构造函数 __construct 中通过工厂方法、自行手动 new 的),而是由外部以参数或其他形式注入的,都属于【依赖注入(DI)】
【依赖注入】是从【应用程序的角度】在描述:应用程序依赖容器创建并注入它所需要的外部资源;
【控制反转】是从【容器的角度】在描述,:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

Laravel服务容器主要承担两个作用:绑定与解析。

namespace App\Http\Controllers;
use App\Users\Repository as UserRepository;
class UserController extends Controller
{
    /**
     * 用户仓库实例
    */
    protected $users;
    /**
     * 创建一个控制器实例
    *
    * @param UserRepository $users 自动注入
    * @return void
    */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

call方法注入

class TaskRepository{
    public function testContainerCall(User $user,Task $task){
        $this->assertInstanceOf(User::class, $user);
        $this->assertInstanceOf(Task::class, $task);
    }
    public static function testContainerCallStatic(User $user,Task $task){
        $this->assertInstanceOf(User::class, $user);
        $this->assertInstanceOf(Task::class, $task);
    }
    public function testCallback(){
        echo 'call callback successfully!';
    }
    public function testDefaultMethod(){
        echo 'default Method successfully!';
    }
}

闭包函数注入

public function testCallWithDependencies()
{
      $container = new Container;
      $result = $container->call(function (StdClass $foo, $bar = []) {
          return func_get_args();
      });
      $this->assertInstanceOf('stdClass', $result[0]);
      $this->assertEquals([], $result[1]);
      $result = $container->call(function (StdClass $foo, $bar = []) {
          return func_get_args();
      }, ['bar' => 'taylor']);
      $this->assertInstanceOf('stdClass', $result[0]);
      $this->assertEquals('taylor', $result[1]);
}

Facade门面

门面相对于其他方法来说,最大的特点就是简洁

  • Laravel 自带了很多 facades ,几乎可以用来访问到 Laravel 中所有的服务。
  • Laravel facades 实际上是服务容器中那些底层类的「静态代理」,相比于传统的静态方法, facades 在提供了简洁且丰富的语法同时,还带来了更好的可测试性和扩展性。
App::make('router')->get('/path', 'PathController@actionName');
# 使用门面模式方式:
Route::get('/path', 'PathController@actionName')
# 门面最后调用的函数也是服务容器的make函数

当 门面没有指定静态函数时,PHP就会调用魔术函数__callStatic

abstract class Facade
{
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        # 门面最后调用的函数也是服务容器的make函数
        return static::$resolvedInstance[$name] = static::$app[$name];
    }

    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }   
}

每个门面类也就是重定义一下getFacadeAccessor函数

class DB extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'db';
    }
}
  • 最好将中间件设想为一系列「层」HTTP 请求在到达您的应用程序之前必须通过。每一层都可以检查请求,甚至完全拒绝它。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK