V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mcfog
V2EX  ›  PHP

虽然并没有贡献者出现,但我还是坚持把我的 PHP 框架堆到完成度很高的程度了

  •  
  •   mcfog · 2019-06-30 23:50:47 +08:00 · 4684 次点击
    这是一个创建于 1980 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果一个框架能用很少的业务代码实现特别多的功能,那么其实就是这个框架内置了大量的惯例,当这些惯例不符合项目预期的时候,如何添加代码精确地改变对应的惯例,而不搞砸其他部分,就会变的很难。经典的例子是各类 CMF,drupal,wordpress,比起框架来已经更接近应用了。

    如果一个框架能实现的功能很多,也很容易修改或定义其中的功能细节,那么这个框架往往需要写非常多的业务代码来填充起这些允许自定义的部分(因为如果这些部分有预设值,这个框架就落回到上一个类型)。一般而言的“重”框架往往是这种类型。

    而一个框架如果要写的业务代码不多,也还是能够轻松的改变其中的功能,那么这个框架往往无法内置很多功能,需要开发者自己动手拼积木。

    以上是我总结的框架的三角原理,业务代码(少),内置功能(多)和内部掌控(易)三者不可得兼。

    作为开发者,我选择放弃内置功能的数量,因为我觉得这是唯一可以由外部弥补的,不属于一个框架本身素质。

    啰嗦了这么多,这是一个以 PSR 为核心的,自带 DI 机制的微框架,其他一切皆可选配。如果你喜欢 Slim,但又嫌弃他自身不模块化没法换轮子,DI 不正宗搞 service locator 反模式,不妨了解一下。如果你还不了解 Slim,还不知道为啥那么多老司机上手就是 Slim,但又懒得四处安利 Slim 这么小的框架究竟好在哪里,那也可以和 Slim 一起看下。

    http://litphp.github.io/blog/2019/06/30/introducing-0-9-0 (全英文预警)

    17 条回复    2019-07-03 17:19:22 +08:00
    thou95
        1
    thou95  
       2019-07-01 00:11:53 +08:00
    支持。
    对框架不框架并不感兴趣,能满足需求就行。
    mywaiting
        2
    mywaiting  
       2019-07-01 01:13:42 +08:00
    现在的 PHP 框架不是随便 php composer 就能堆出来了么?
    skiy
        3
    skiy  
       2019-07-01 09:50:26 +08:00
    像楼上所说,可以堆出来的了。
    用 ORM,ROUTER + VUE 中的各前端集成平台。
    laojiaqing
        4
    laojiaqing  
       2019-07-01 11:19:31 +08:00
    thx
    dvaknheo
        5
    dvaknheo  
       2019-07-02 12:13:36 +08:00
    看了一下,没什么卖点啊。
    DI 机制不就是个大数组,可以替换框架里的组件。
    现在没有“能在不改变源代码情况下 替换原先组件”的 框架是不合格的。

    而且这个框架 ,看上去入门没一眼就能用
    dvaknheo
        6
    dvaknheo  
       2019-07-02 12:23:43 +08:00
    Air , Bolt , Nexus ,Nimo 这些命名,你又不是要作为很通用的组件,何必让用户难理解
    再说入口文件 Voltage 里的 hello_world :

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

    class HelloAction extends AbstractAction
    {
    public function __construct()
    {
    $this->responseFactory = new ResponseFactory();
    }

    protected function main(): ResponseInterface
    {
    return $this->json()->render([
    'hello' => 'world',
    'method' => $this->request->getMethod(),
    'uri' => $this->request->getUri()->__toString(),
    ]);
    }
    }

    $app = new App(new HelloAction());

    $request = ServerRequestFactory::fromGlobals();
    $response = $app->handle($request);
    $emitter = new SapiEmitter();
    $emitter->emit($response);

    ```

    搞这么复杂,你瞧瞧 DNMVCS 就很简单了

    ```php
    <?php
    require(__DIR__.'/../headfile/headfile.php');

    $options=[];
    if (defined('DNMVCS_WARNING_IN_TEMPLATE')) {
    $options['is_dev']=true;
    $options['skip_setting_file']=true;
    echo "<div>Don't run the template file directly </div>\n";
    }

    $path=realpath(__DIR__.'/..');
    $options['path']=$path;
    $options['namespace']='MY';
    \DNMVCS\DNMVCS::RunQuickly($options, function () {
    });
    ```
    dvaknheo
        7
    dvaknheo  
       2019-07-02 12:28:05 +08:00
    DNMVCS 卖点之一是: 如果你写代码引用到 DNMVCS 的类,说明要么就是你作为老大,不得不用到,要么就是你想法有问题,小弟不要去引用 框架里的代码。
    这样你切换成其他框架都容易。
    DNMVCS 不引用任何第三方类库。也是卖点,稳定,不会因为第三方有问题而连带出问题。

    当然,DNMVCS 最基本的思想就是 把业务逻辑要放到 service 里。 不会导致 controller 或 model 层 上千行代码
    ben1024
        8
    ben1024  
       2019-07-02 12:57:30 +08:00
    支持下,还是喜欢重型框架应用体验
    mcfog
        9
    mcfog  
    OP
       2019-07-02 12:57:33 +08:00 via Android
    @dvaknheo 建议看看 phptherightway 多了解了解 modern php 的成果,还有关于 di 的概念也可以多看看,php 写框架太简单很容易给人错误的认知
    mcfog
        10
    mcfog  
    OP
       2019-07-02 13:07:26 +08:00 via Android
    @ben1024 各有优点,可是作为手痒要写框架的个人来说,重型的框架工程量太大了,控制规模才能有精力精雕细琢
    dvaknheo
        11
    dvaknheo  
       2019-07-02 18:45:30 +08:00
    @mcfog 不以解决问题为导向的 PHP 代码都不是好代码。

    回头看了 phptherightway 的中文版,不是老外的月亮就圆。

    如果不为了解决 耦合 问题, 那么需要 DI 么?

    尽管 PHP 不断升级为成熟的、面向对象的语言,但它作为模板语言 没有改善多少。编译模板,比如 Twig 或 Smarty* ,提供了模板专用的新语法,填补了这片空白。

    Smarty 都死了多少年了?
    Apache 和 PHP —— 用 apache 的都是老项目了。
    mcfog
        12
    mcfog  
    OP
       2019-07-02 18:50:17 +08:00
    @dvaknheo 你说的都挺对的,感谢你的关注
    dvaknheo
        13
    dvaknheo  
       2019-07-03 13:29:38 +08:00
    再来个调试方面的问题,你能从堆栈里看出什么信息么?

    #0 xx\Action\HomeAction->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #1 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/voltage/RouterDispatchHandler.php:30]
    #2 Lit\Voltage\RouterDispatchHandler->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #3 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:43]
    #4 Lit\Nimo\Middlewares\AbstractMiddleware->delegate() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:75]
    #5 Lit\Nimo\Middlewares\MiddlewarePipe->loop() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:28]
    #6 Lit\Nimo\Middlewares\MiddlewarePipe->Lit\Nimo\Middlewares\{closure}()
    #7 call_user_func() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Handlers/CallableHandler.php:38]
    #8 Lit\Nimo\Handlers\CallableHandler->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #9 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:43]
    #10 Lit\Nimo\Middlewares\AbstractMiddleware->delegate() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:75]
    #11 Lit\Nimo\Middlewares\MiddlewarePipe->loop() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:65]
    #12 Lit\Nimo\Middlewares\MiddlewarePipe->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:33]
    #13 Lit\Nimo\Middlewares\AbstractMiddleware->process() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:78]
    #14 Lit\Nimo\Middlewares\MiddlewarePipe->loop() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:28]
    #15 Lit\Nimo\Middlewares\MiddlewarePipe->Lit\Nimo\Middlewares\{closure}()
    #16 call_user_func() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Handlers/CallableHandler.php:38]
    #17 Lit\Nimo\Handlers\CallableHandler->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #18 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:43]
    #19 Lit\Nimo\Middlewares\AbstractMiddleware->delegate() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/bolt/Middlewares/EventsHub.php:57]
    #20 Lit\Bolt\Middlewares\EventsHub->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:33]
    #21 Lit\Nimo\Middlewares\AbstractMiddleware->process() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:78]
    #22 Lit\Nimo\Middlewares\MiddlewarePipe->loop() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:28]
    #23 Lit\Nimo\Middlewares\MiddlewarePipe->Lit\Nimo\Middlewares\{closure}()
    #24 call_user_func() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Handlers/CallableHandler.php:38]
    #25 Lit\Nimo\Handlers\CallableHandler->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #26 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:43]
    #27 Lit\Bolt\Middlewares\RequestContext->delegate() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/bolt/Middlewares/RequestContext.php:35]
    #28 Lit\Bolt\Middlewares\RequestContext->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:33]
    #29 Lit\Bolt\Middlewares\RequestContext->process() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:78]
    #30 Lit\Nimo\Middlewares\MiddlewarePipe->loop() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Middlewares/MiddlewarePipe.php:65]
    #31 Lit\Nimo\Middlewares\MiddlewarePipe->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/MiddlewareTrait.php:33]
    #32 Lit\Nimo\Middlewares\AbstractMiddleware->process() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/bolt/BoltApp.php:60]
    #33 Lit\Bolt\BoltApp->main() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/nimo/Traits/HandlerTrait.php:20]
    #34 Lit\Nimo\Handlers\AbstractHandler->handle() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/zendframework/zend-httphandlerrunner/src/RequestHandlerRunner.php:95]
    #35 Zend\HttpHandlerRunner\RequestHandlerRunner->run() called at [/mnt/d/MyWork/sites/zzz/z/myproject/vendor/litphp/runner-zend-sapi/BoltZendRunner.php:21]
    #36 Lit\Runner\ZendSapi\BoltZendRunner::run() called at [/mnt/d/MyWork/sites/zzz/z/myproject/public/index.php:9]

    顺便对比 DNMVCS 的:

    #0 MY\Controller\Main->index() called at [/mnt/d/MyWork/sites/DNMVCS/src/Core/Route.php:190]
    #1 DNMVCS\Core\Route->run() called at [/mnt/d/MyWork/sites/DNMVCS/src/Core/App.php:246]
    #2 DNMVCS\Core\App->run() called at [/mnt/d/MyWork/sites/DNMVCS/src/Core/App.php:87]
    #3 DNMVCS\Core\App::RunQuickly() called at [/mnt/d/MyWork/sites/DNMVCS-FullTest/public/index.php:13]

    都是在控制器方法里加这段代码

    echo '<pre>';
    debug_print_backtrace(2);
    echo '</pre>';exit;
    mcfog
        14
    mcfog  
    OP
       2019-07-03 14:10:19 +08:00
    @dvaknheo 谢谢,我还真没想到这个点,我可以做一些优化,把每次中间件调用增加的堆栈个数优化掉几个。可是没有中间件的堆栈和有中间件的堆栈并没有什么可比性。如果你能用少量的堆栈实现 psr15 中间件的串联,可以给我看一下实现我学习一下。
    doyouhaobaby
        15
    doyouhaobaby  
       2019-07-03 14:28:37 +08:00
    @dvaknheo @mcfog 经过一定抽象的都有比较长的 backtrace,做一个平衡罢了。
    dvaknheo
        16
    dvaknheo  
       2019-07-03 16:32:46 +08:00
    @doyouhaobaby 问题是,这解决了什么问题,“优雅” ?

    不,是一群 JAVA 化的人员把大家带入的坑而已。
    psr6 和 psr16 的故事。


    如果坑了足够多的人,就可以让以后的学习者不得不捏着鼻子用。

    中间件明明可以用两个接口,before ,after,却为了优雅,函数化,做成了一个。
    不去考虑是否方便调试。
    这背离了 PHP 方便,快速开发的初衷。

    public function handle($request, Closure $next)
    {
    ////
    return $next($request);
    }
    mcfog
        17
    mcfog  
    OP
       2019-07-03 17:19:22 +08:00
    @dvaknheo 不了解中间件模式解决了什么问题并不是什么值得自豪的事情,建议你自己多了解一下,作出更有意义的批评。我不知道你对 Java 的敌意是哪里来的,但据我所知 http 中间件更多源自 NodeJS 社区的启发。至于 PSR6,实际上讨论过程中拒绝了来自 Doctrine 社区的更偏向 OO 更复杂的提案,PSR16 也并非取代或否定 PSR6,不知道你说的所谓故事是什么样的

    至于你说把中间件接口做成两个更好,方便调试,我难以赞同。做成 before after 以后就连基本的 try catch 或有条件跳过 next 逻辑都很难做好,我也无法想象到什么场景会造成调试难易的差别
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2589 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:10 · PVG 11:10 · LAX 19:10 · JFK 22:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.