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

2019-06-30 23:50:47 +08:00
 mcfog

如果一个框架能用很少的业务代码实现特别多的功能,那么其实就是这个框架内置了大量的惯例,当这些惯例不符合项目预期的时候,如何添加代码精确地改变对应的惯例,而不搞砸其他部分,就会变的很难。经典的例子是各类 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 (全英文预警)

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

而且这个框架 ,看上去入门没一眼就能用
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
2019-07-02 12:28:05 +08:00
DNMVCS 卖点之一是: 如果你写代码引用到 DNMVCS 的类,说明要么就是你作为老大,不得不用到,要么就是你想法有问题,小弟不要去引用 框架里的代码。
这样你切换成其他框架都容易。
DNMVCS 不引用任何第三方类库。也是卖点,稳定,不会因为第三方有问题而连带出问题。

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

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

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

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

Smarty 都死了多少年了?
Apache 和 PHP —— 用 apache 的都是老项目了。
mcfog
2019-07-02 18:50:17 +08:00
@dvaknheo 你说的都挺对的,感谢你的关注
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
2019-07-03 14:10:19 +08:00
@dvaknheo 谢谢,我还真没想到这个点,我可以做一些优化,把每次中间件调用增加的堆栈个数优化掉几个。可是没有中间件的堆栈和有中间件的堆栈并没有什么可比性。如果你能用少量的堆栈实现 psr15 中间件的串联,可以给我看一下实现我学习一下。
doyouhaobaby
2019-07-03 14:28:37 +08:00
@dvaknheo @mcfog 经过一定抽象的都有比较长的 backtrace,做一个平衡罢了。
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
2019-07-03 17:19:22 +08:00
@dvaknheo 不了解中间件模式解决了什么问题并不是什么值得自豪的事情,建议你自己多了解一下,作出更有意义的批评。我不知道你对 Java 的敌意是哪里来的,但据我所知 http 中间件更多源自 NodeJS 社区的启发。至于 PSR6,实际上讨论过程中拒绝了来自 Doctrine 社区的更偏向 OO 更复杂的提案,PSR16 也并非取代或否定 PSR6,不知道你说的所谓故事是什么样的

至于你说把中间件接口做成两个更好,方便调试,我难以赞同。做成 before after 以后就连基本的 try catch 或有条件跳过 next 逻辑都很难做好,我也无法想象到什么场景会造成调试难易的差别

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/578819

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX