跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • DuckPhp 1.2.4 发布,终极架构,文档完善了
未分類
18 5 月 2020

DuckPhp 1.2.4 发布,终极架构,文档完善了

DuckPhp 1.2.4 发布,终极架构,文档完善了

資深大佬 : dvaknheo 1

项目地址: https://github.com/dvaknheo/duckphp
作者 QQ: 85811616
官方 QQ 群: 714610448

phpstan 第 7 级检查通过。php-cs-fixer 代码风格通过。phpunit 全覆盖测试通过。

名称统一成了 DuckPhp,和命名空间一样。

重复一下 DuckPhp 的特性:
+ 可以在不改动库文件下,替换所有实现。
我用 CodeIgniter 的时候,基本上没见到个 CodeIgniter 系统代码是官方原版的。都是各种魔改。
Composer 时代之后,直接改 vendor 的文件确实是不可取的
所以满足在不改动库文件下,替换所有实现这是对现代框架的基本要求。不实现这个目标的框架没存在意义。

+ 可以非固定全站使用的框架。
很多框架都要要求你配置整站才能使用,DuckPhp 很灵活,不需要配置成整站。
甚至启用自带扩展能做到连 Web 服务器都不用配置的单一入口文件模式。
还有一种玩法是 A ,B 两个项目独立开发,然后合在同一个服务器上。
其他框架很麻烦,命名空间都是用 App,路由处理还要折腾很多。
DuckPhp 不同项目不同命名空间,B 项目作为 A 项目的插件使用。

+ DuckPhp 秉着 代码和 DuckPhp 关联越少越好的原则
核心工程师写的非业务核心代码才会和 DuckPhp 耦合。
应用工程师写的业务代码是不和 DuckPhp 耦合的。

+ DuckPhp 是无第三方依赖的单一的 Composer Library
这点很重要么? 很重要。引用的第三方组件出了 Bug 人家升级了怎么办。
Library 则很方便的插入第三方框架里使用。
DuckPhp 工程的初始化就是 复制 template 目录,修改相应模板。
甚至可以直接运行 template 目录。

—

从 CURD 角度的应用工程师角度来看,基本不需要动什么。

使用 DuckPhp 的感觉就是,默认的就已经足够了。

应用工程里那些高级的东西,让核心工程师来做。
而核心工程师呢,如果不满足,那么就调选项。
如果选项还不行,那就入口类里调整。
更高级的是自己做组件和替换默认组件。
对于应用工程师,就看那些 Helper 函数多出来什么就够了。
var_dump(ControllerHelper::GetExtendStaticMethodList());

最高级的玩法是把当前工程 A 作为扩展给 B 工程复用。
也没什么难度,入口类里加额外代码就是。(引入 AppPluginTrait)

1.2.3 版本,我在 yii3 demo 上内嵌了个 DuckPhp 作为实现版本

https://github.com/dvaknheo/yii-demo

在入口 index.php 处拦截如果 DuckPhp 能实现,则用 DuckPhp 的实现版本,否则继续
所有 DuckPhp 版本的实现的文件,都在一个目录下,可以对比一下。
https://github.com/dvaknheo/yii-demo/tree/for_duckphp/app
之前也折腾过 laravel 的 demo, 结果丫自己的 auth demo 我看的都绕半天,何况其他小白。

用 phpunit-codecoverage 看了一下 thinkphp 5.1 hello world 。1052 / 19241 行代码。
也就是不干什么事情都至少有 1000 行代码空跑了。DuckPhp 是 339/5252 行,所以 DuckPhp 是高效的。
当然,这只是对性能的粗略估计。比如 一个 autoloader 的 file_exists 判断性能上就能顶很多行
(尤其是我在 wsl1 环境下 IO 性能惨不忍睹。
至于 Laravel,我有空看一下是不是跑了一万行代码。

DuckPhp 的 swoole 支持是有的,只不过现在不作为重点了,workerman 有空的话我再看看。
DuckPhp 切换成这些模式是无缝的。 只是我不觉得 web 不是 swoole/workerman 该做的主战场。

现在想找个能很好的演示 DuckPhp 的工程来做。演示一下 DuckPhp 的魅力。

大佬有話說 (36)

  • 資深大佬 : littleylv

    其他还没看,你这个名字能改一下吗? Php 看着超级别扭。专有名词不用按照驼峰规范来的,直接 DuckPHP 没问题的,DuckPhp 反而看着别扭

  • 資深大佬 : lifeintools

    大概看了 一圈 没看懂。。希望介绍能言简意赅一些

  • 資深大佬 : lscho

    同一,太别扭

  • 資深大佬 : xnode

    可以叫 DoubleDuck 中文 双鸭

  • 資深大佬 : jqh

    + DuckPhp 秉着 代码和 DuckPhp 关联越少越好的原则
    核心工程师写的非业务核心代码才会和 DuckPhp 耦合。
    应用工程师写的业务代码是不和 DuckPhp 耦合的。
    ————————————————————
    这样做的意义在哪里?用框架不就是为了不重复造轮子吗?框架提供稳定成熟的基础功能,让工程师专注于业务的开发,你让核心工程师去造这些轮子我敢说大部分质量都是很糟糕的,至少我待过的公司中使用自研框架(无框架)的公司,代码质量都是不怎么样的。毕竟一个成熟的开源框架,每个细节的设计都是经过成千上万个项目检验提炼后的成果,很多公司所谓自研核心组件就是想当然和幼稚无意义的重复实现。

    ControllerHelper::GetExtendStaticMethodList()
    ————————————————————-
    还自创代码风格??这么多千奇百怪的风格不累吗?自动加载都知道用 composer PSR4 规范了?编码风格也不能统一一下?

    至于 Laravel,我有空看一下是不是跑了一万行代码。
    ————————————————————–
    现在还有纠结代码行数的,实际上绝大多数用 PHP 的公司都没必要纠结这点代码行数,开发效率和稳定性才是重中之重

  • 資深大佬 : littleylv

    + DuckPhp 是无第三方依赖的单一的 Composer Library
    这点很重要么? 很重要。引用的第三方组件出了 Bug 人家升级了怎么办。

    ————————————————————–

    这点我不敢苟同。现在那么多的优秀组件(特别是 symfony 家的组件),那么多好的轮子,为什么一定要自己造。“引用的第三方组件出了 Bug”? symfony 家社区那么多用户,有 bug 也是很快发现或很快修复。再说了别人有 bug,你自己造的轮子也有可能有 bug 呀

  • 資深大佬 : james122333

    支持主造轮子
    可以证明自己不是搬运工
    成千上万项目检验只能说给非专业的人听

  • 資深大佬 : littleylv

    “php-cs-fixer 代码风格通过。”

    ————————————————————–

    我不知道主用的谁家的代码风格,我稍微看了代码 https://github.com/dvaknheo/duckphp/blob/master/src/Ext/DBManager.php:

    — psr-1 规定 方法名称 必须 符合 camelCase 式的小写开头驼峰命名规范。:
    public static function CloseAllDB()
    public static function DB_W()
    public function _DB($tag = null)
    public function _DB_W()
    public function _onException()
    public function OnException()

    — psr-1 规定 类的属性名 应该 在一定的范围内保持一致:
    protected $before_get_db_handler = null;
    protected $use_context_db_setting = true;
    protected $beforeQueryHandler = null;

  • 主 資深大佬 : dvaknheo

    @littleylv 我系统命名空间是用 DuckPhp,所以统一成 DuckPhp 。 要不,还得把命名空间全调整成 DuckPHP ?

    @jqh 不是说核心工程师造轮子,是核心工程师调轮子。应用工程师一个 DuckPhp 命名空间的东西也用不到。
    DuckPhp 用 phpstan 检查过规范,phpunit 单元覆盖测试 100% 。

    ControllerHelper::GetExtendStaticMethodList() => 这里只是个简写, 其实直接在 MyProjectBaseHelperControllerHelper 里字节加就行。 这是写插件的时候的额外方法。

    是有自动加自的。

    现在还有纠结代码行数的 。
    ////
    fpm 模式下,空跑上万行和 和 100 行区别大了。 而且上万行的代码,意味着核心工程师想调整写功能也不好找。

    “引用的第三方组件出了 Bug”? symfony 家社区那么多用户,有 bug 也是很快发现或很快修复。

    ////
    有这么一个框架,引用了低版本的 symfony 组件。symfony 后来升级了。

    再说了别人有 bug,你自己造的轮子也有可能有 bug 呀
    ////
    所以现代框架就必须要有出 Bug 的时候可以不硬改系统代码,在工程里改正的方法啊。

  • 主 資深大佬 : dvaknheo

    @littleylv .php_cs 文件, 就额外几条规则。你这里说的,没用 php-cs-fixer fix 检查出来。

    “`
    <?php
    $header = <<<‘EOF’
    DuckPhp
    From this time, you never be alone~
    EOF;
    $finder = PhpCsFixerFinder::create()
    ->files()
    ->in(__DIR__.’/src’)
    ->name(‘*.php’)
    ;
    return PhpCsFixerConfig::create()
    ->setRiskyAllowed(true)
    ->setRules([
    ‘@PSR2’ => true,
    ‘header_comment’ => [
    ‘commentType’ => ‘PHPDoc’,
    ‘header’ => $header,
    ‘separate’ => ‘none’,
    ‘location’ => ‘after_declare_strict’,
    ],
    ‘declare_strict_types’ => true,
    ‘binary_operator_spaces’=>true,
    ])
    ->setFinder($finder)
    ->setUsingCache(false);
    “`

    public function _DB($tag = null) 这样的方法是对应 public function DB($tag = null) 的。

    用于外部回调。 下划线开始的代码,算是一种特殊风格。

    public function _onException()
    public function OnException() 刚注意到这应该用 _OnException 。 代码多了,有些地方没注意得过来。

    欢迎大家到 Github 上提 Issue 或者在 QQ 群里讨论

  • 資深大佬 : iidestiny

    主是不是对 Laravel 有什么偏见。。。

  • 主 資深大佬 : dvaknheo

    @iidestiny
    Laravel 不能节省运行效率和开发效率。 违背了 PHP 简洁之道。

    随手举例子

    + blade 模板 违背了 PHP 代码就是视图的原则
    + 滥用 ArrayIterator foreach, 使得没法 dump
    + orm 使得调试更麻烦了
    + 退化到路由表了。有简单的文件路由不用。
    + 中间件使得调用关系复杂化。

  • 資深大佬 : HiCode

    看着心疼主,又不是人民币,没办法得到别人的喜欢的。

    我就不爱做这事了……

  • 資深大佬 : wowiwj

    laravel 不能节省开发效率和运行效率的结论从哪里得出来的?感觉主可能对 php 有什么误解,最好拉一些实际例子列举一些自己轮子优势,这样大家好坏看起来更直观一些,也更有说服力

  • 主 資深大佬 : dvaknheo

    @wowiwj
    laravel 的运行效率,已经有太多例子了。
    laravel 的开发效率:不要指望一个智力水平只有高中的 php 新手去使用并了解其中原理。

    最好拉一些实际例子列举一些自己轮子优势。
    ////
    我 fork 了一个 yii3 demo 的分支,用 DuckPhp 1.2.3 实现的。输出和 yii3 的一模一样。

    除了入口文件,其他工程文件都在同一个目录下

    https://github.com/dvaknheo/yii-demo/tree/for_duckphp/app

    可以看 yii3 还是 DuckPhp 更容易明白。DuckPhp 更加朴实无华,不用那么花哨就解决问题。

    之前在我本机弄了 laravel 自带的 auth 的版本,发现 laravel auth 连我都没能弄清楚,怎么可能会有国内项目用他那套做验证,都是自己从头起一套更容易。 后面是卡在验证器部分了。 要在不用 laravel 框架的情况下实现和 laravel 做表现一致的验证。后面回头做 DuckPhp 的代码了就没管这个。

    @HiCode 谢谢。我希望能有一小撮人搞起。在写文档的时候,总没有底气不知道别人能否看明白。DuckPhp 的精妙之处,在使用之后会明白的。但是我做得出来,说出来就一塌糊涂。DuckPhp 也有些地方,总感觉可以做得更好,但是总是缺一个人提醒一下。

  • 資深大佬 : rootx

    支持主!

  • 資深大佬 : DavidNineRoc

    随便点开了一个文件,看到了 Core_App
    所以主是用 sanke 还是 camel 呢。

    对于主说的话,我就随便反驳几个。
    1. Laravel 不能节省开发效率,这句话你是框架第一人。你写个队列任务,写个数据库操作
    2. 简单的文件路由,你都知道简单了,为什么还要纠结这个问题呢,文件路由怎么实现 path parameter 呢。
    3. 如果一个项目没有中间件,我大概就知道这个项目怎么做登录验证的那种模块了,估计就是每个文件 include auth.php
    4. 前面的人也说了,你居然相信你会超过 symfony 家,别人一个人我就不说了,一个社区你想怎么比

    从 CURD 角度的应用工程师角度来看,你都觉得框架不好了,我觉得不用原生 PHP 的都是在放屁 |(-_-)

  • 資深大佬 : explore365

    |支持主

  • 主 資深大佬 : dvaknheo

    @DavidNineRoc

    1 队列任务不是 Web 框架必备的部分,队列或者应该是单独的一个库。数据库也不是。但是作为常用组件,DuckPhp 通过默认扩展的方式提供主从数据库的支持。另一个默认扩展,就是分页了。 分页在各应用里绝对都是很折腾的方式,所以 DuckPhp 也带了基础的分页,并很容易改写。

    2 文件路由,namespace 分割,如果有更特殊需求,加路由钩子。

    3 路由前后钩子。中间件搞得堆栈混乱一堆。中间件还存在为调用顺序折腾的事。 如果路由钩子多起来,那么我会提供调用方式调整的方法,但是希望是手动。

    4 一个社区也是由一小撮人慢慢发展起来的。并不是说 symfony 不好。为什么能推广开的是 laravel 而不是 symfony 我很奇怪。 比如 html 编码。 我提供了一个默认方式,zend framework 有更好的方式,你可以很容易的去替换成 zend framework 。symfony 的例子意思是可靠性最好不要建立在 第三方基础上,而是自己有实现,也可替换成第三方实现。

    因为我闭门造车,很多小的细节不可避免的有问题,目前就是希望能有一小撮人一起来讨论,做好。

  • 主 資深大佬 : dvaknheo

    @DavidNineRoc
    3. 如果一个项目没有中间件,我大概就知道这个项目怎么做登录验证的那种模块了,估计就是每个文件 include auth.php

    这个问题我再说明一下,我刚才答错了。
    DuckPhp 项目,推荐的是用 PHPer 最习惯的方式,在控制器基类构造函数里做权限判断。好处是你从代码看起的时候不会发懵:为什么这里会有个验证? 这也就是 DuckPhp 尽量避免的,这玩意从哪里来。

    我答成了使用第三方类 auth 类做验证了。
    如 template 目录下的例子。

    http://duckphp.demo.dev/full/public/u/index.php/login

    对应的文件应该是 template/full/public/u/app/Controller/Main.php (暂时别吐槽为什么文件这么长了。
    但是没看到 login 方法。
    因为在
    template/full/public/u/app/Base/App.php 的 oninit 里有这么几句。
    $this->options[‘ext’][‘UserSystemDemoBaseApp’] = true;
    $path = realpath($this->options[‘path’].’../../auth/’);
    $this->assignPathNamespace($path, ‘UserSystemDemo’);
    后两句是 autoload 添加 ‘UserSystemDemo’ 命名空间。
    重点是第一句
    把 template/full/public/auth 这个项目作为扩展来用于 auth.
    template/full/public/auth/Base/App.php 只需要一句,就把这个独立工程可插件化了。
    use AppPluginTrait;

    独立运行 auth 项目的入口是
    http://duckphp.demo.dev/full/public/auth.php

  • 資深大佬 : ruoge3s

    # 20 那个,在构造器里加权限判断,耦合太严重了。

  • 資深大佬 : ruoge3s

    1. 建议主可以多看看一看设计模式。
    2. 自己写一些框架组件没什么问题的。有些东西自己写了,才会更能感受到别人写的一部分东西确实很优秀。借鉴人家优秀的东西,让自己的框架、组件更优秀,让自己更优秀吧。

  • 主 資深大佬 : dvaknheo

    @ruoge3s 控制器的构造器就是干这样的活的,还觉得耦合严重。。。
    控制器又不需要继承系统基本类,一看就明白。
    给你看个耦合严重的控制器例子吧。

    “`
    namespace AppHttpControllers;

    use IlluminateFoundationAuthAccessAuthorizesRequests;
    use IlluminateFoundationBusDispatchesJobs;
    use IlluminateFoundationValidationValidatesRequests;
    use IlluminateRoutingController as BaseController;

    class Controller extends BaseController
    {
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
    }
    “`
    这时候,你就的去看 BaseController 里有什么,会影响到什么。
    还有 AuthorizesRequests DispatchesJobs ValidatesRequests 都有什么功能。
    似乎这些不管也无所谓。

    控制器基本不会复用,复用的是 service,业务逻辑层。

    keep it simple stupid.

  • 主 資深大佬 : dvaknheo

    DuckPhp 1.2.3 到 1.2.4 版本有个显著改变是之前组件都没继承基类,实现什么接口。只使用 SingletonEx trait 做可变单例。

    按 MyComponent::G()->init(array $optioins, $context=null): this;
    这样的约定初始化(可以想象成 ServiceProvider.

    1.2.4 之后,各组件使用 MyComponent extends DuckPhpCoreComponentBase , ComponentBase implements ComponentInterface,这样的方式,多了一个继承,内部实现一个接口。

    实际上你编写扩展,也只需要满足约束 MyComponent::G()->init(array $options, $context=null): this; 就行了,没必要 实现 ComponentInterface 的所有接口

    ComponentBase 帮你过滤你只需要的 $options 选项。 拆分 init() 为 initOptions($options) initContext() 两个空方法以便于你的继承。

    以上这些,只是核心工程师需要了解的。应用工程师用不到。
    影响应用工程师的是少量选项,方法名又因为名称不满意,细调了,不兼容了。

    核心工程师有没有会被版本升级恶心的事呢? 有,继承系统类的时候,或许系统类的类型会调整成强类型,签名不同了。

    最后,还可能会有什么问题呢?
    Helper 的函数名字冲突,比如你在旧版本的 Helper 加了个函数, 升级后函数名相同,但签名不同,这也是不太可能出现的情况。

  • 資深大佬 : beastk

    其实我还在用 php5.2

  • 資深大佬 : jqh

    @dvaknheo

    不是说核心工程师造轮子,是核心工程师调轮子。应用工程师一个 DuckPhp 命名空间的东西也用不到。
    DuckPhp 用 phpstan 检查过规范,phpunit 单元覆盖测试 100% 。
    ——————————————————–
    “应用工程师一个 DuckPhp 命名空间的东西也用不到”,你这句话翻译一下就是:这个框架基本什么基础功能都不提供。

    那你让“核心工程师”调什么?你有提供 HTTP 请求和响应处理功能有吗?配置文件功能有吗?文件处理功能有吗?缓存工具有吗?参数表单验证工具有吗?还有更多基础功能你都没有,那你怎么让“核心工程师”不造轮子?

    最终的结果就是各种所谓的“核心工程师”拿到你的框架就是群魔乱舞各种瞎写,最后出来的就是惨不忍睹、很难维护的糟糕代码,这也是很多所谓自研框架公司的现状。

    + blade 模板 违背了 PHP 代码就是视图的原则
    + 滥用 ArrayIterator foreach, 使得没法 dump
    + orm 使得调试更麻烦了
    + 退化到路由表了。有简单的文件路由不用。
    + 中间件使得调用关系复杂化。
    ——————————————————–
    PHP 代码是视图的原则??这都 2020 年了,您还崇尚 HTML 和 PHP 混编呢?这写出来的代码能维护?大清早就灭亡了亲;
    orm 使得调试更麻烦了,laravel 提供了多种方式可以让 ORM 转化成 sql 调试,调试虽然麻烦了一点,但 ORM 带来的便利程度远远大于麻烦程度;
    退化到路由表了。有简单的文件路由不用,中间件使得调用关系复杂化,从这个描述就说明,你根本没理解 laravel 路由和中间件的好用之处。

    中间件最大的好处就是能把各种与业务无直接关联的代码抽象出来,放在中间件里面,每个业务控制器 action 就可以通过配置轻松增减、切换各种不同的中间件,而不需要改动业务的一行代码。比如日志收集、登陆验证、接口权限判断等等,我甚至可以实现各种逻辑不同的登陆中间件,随意切换,如果你把这些跟业务无关的代码放在控制器中,那最终只会造成你代码杂乱、臃肿和难以维护。
    那么 laravel 的路由结合中间件的配置,简直不要太好用,我可以轻松给各种路由进行分组;尤其是方便了开发者写扩展包,可以以最大的自由度定义扩展包路由,以及其实用的中间件,简直太牛逼了。其他的大部分框架,都没有这么好用的路由,也难怪 laravel 的生态如此强大,可以说 laravel 的高质量的第三包扩展包的数量可以吊打任何一款 PHP 框架。

    可见一个成熟的设计是多么重要,细节和生态才是一个框架的根本。laravel 的方方面面的设计,其实都是兼顾了普通开发者和第三方扩展包开发者的需求的,但很可惜,很多人并不理解其中的意义。

    而主说的中间件使得调用关系复杂化,这完全可以说是你的水平不够,中间件的配置入口就是公共配置和路由配置两种,能复杂到哪去?堆栈调用复杂?我宁愿看多几十行堆栈调用,也不愿写业务代码和与业务无关代码混杂在一起像乱麻一样的代码。

    之前在我本机弄了 laravel 自带的 auth 的版本,发现 laravel auth 连我都没能弄清楚,怎么可能会有国内项目用他那套做验证
    ——————————————————–
    你这个把我看笑了,你是看不起其他程序员,还是太看得起自己?? laravel auth 你都整不明白,还好意思大言不惭说这个不行那个不行?建议主保持谦逊的态度,对不懂的东西不要乱评判,看了主的发帖纪录,就是一直在评判自己没搞懂的东西

  • 主 資深大佬 : dvaknheo

    @jqh
    “应用工程师一个 DuckPhp 命名空间的东西也用不到”,你这句话翻译一下就是:这个框架基本什么基础功能都不提供。
    —-
    是有这么一个基本用不到的功能:是你可以无缝替换成另一个框架。 翻译就是无耦合。

    HTTP 请求, $_GET,$_POST 还没死绝呢。PHP 官方又没出一个自己的 psr 接口。PHP 为什么比 Java 容易明白没?
    Framework 和 Library 的区别知道么。 非得所有的都要要你 framework 里的么?
    没关系,核心工程师怎么偷换实现都不会乱, 反正应用工程师看不到。

    PHP 代码是视图的原则??这都 2020 年了,您还崇尚 HTML 和 PHP 混编呢?这写出来的代码能维护?大清早就灭亡了亲;
    那么非 PHP 的视图模板里写 sql 你见过没。Widget 里一个超级对象你见过没。PHP 视图的原则是不做计算,只输出,而不是混编。
    [Smarty 出了这么多年,PHPer 又退化到用 PHP 来写视图模板了]

    orm 使得调试更麻烦了,laravel 提供了多种方式可以让 ORM 转化成 sql 调试,调试虽然麻烦了一点,但 ORM 带来的便利程度远远大于麻烦程度;
    调试是重要工作。而且 orm 需要多学一层,所以又过滤了一部分懒人。

    PHP 最大的好处之一就是随时改业务代码。
    DuckPhp 好处之一就是你可以把你的中间件做成独立的工程独立使用。应该说是可以把独立工程变成“中间件”,之前回答里都有了,我上面没演示的是 view 和 配置,也可以 重载。
    DuckPhp 好处之二就是这些东西都是显式表达的,你不会看到“哇靠,这东西从哪里冒出来的,究竟错在哪里”。

    如果你把业务代码放在控制器里,那等到 10k 行控制器的时候维护起来就痛苦死了。

    日志收集,登陆验证,接口权限判断这些,都是核心工程师的职责。所以他们会告诉应用工程师:继承这个控制器基类就够了。想改这些,在基类里改就是。

    我水平不够,所以只能用 PHP 这种语言。现在高水平的都去用 Java ,Go 了。
    所以我写的框架也只是适用于那些想用 PHP 快速开发的人。
    [Laravel 是很优雅的框架,不应该使用 PHP 这种不优雅的语言,应该使用更好的语言来写。]

    Laravel 默认的 auth 代码的流程我后来是弄清楚了。搞那么复杂的目的是为了有效的过滤智力低下的懒惰的 CURD 程序员。

  • 資深大佬 : nicoljiang

    Laravel 是很优雅的框架,不应该使用 PHP 这种不优雅的语言,应该使用更好的语言来写。

    +1
    Laravel 的作者继续耕耘 .NET 方向多好

  • 資深大佬 : jqh

    @dvaknheo

    “`php
    public function postLogin(Request $request)
    {
    $vaptcha = Vaptcha::make();

    // 验证验证码是否正确
    if (! $vaptcha->validate()) {
    // 验证不通过,返回错误提示信息到前端
    return $this->error($vaptcha->getError());
    }

    $credentials = $request->only([$this->username(), ‘password’]);
    $remember = (bool) $request->input(‘remember’, false);

    // 验证参数
    $validator = Validator::make($credentials, [
    $this->username() => ‘required’,
    ‘password’ => ‘required’,
    ]);

    if ($validator->fails()) {
    return $this->validationErrorsResponse($validator);
    }

    // 登陆并返回成功信息
    if ($this->guard()->attempt($credentials, $remember)) {
    return $this->sendLoginResponse($request);
    }

    // 返回失败信息
    return $this->validationErrorsResponse([
    $this->username() => $this->getFailedLoginMessage(),
    ]);
    }
    “`

    这里我截取一段使用 laravel auth 实现的登陆功能,换成你的说法,就是你口中“应用工程师”该写业务代码,多简洁易懂,这代码不好维护吗?跟业务无关吗?

    而其中$this->guard()->attempt 这样的 auth 底层实现,就是你口中“核心工程师”写的登陆的轮子,框架内置的轮子不比大部分“核心”工程师写的优质、好用许多吗?

    laravel 这样设计的更强大之处在于,“应用工程师”甚至不必关心登陆验证的数据存储细节,例如你是想使用 session 登陆、还是 auth2.0 登陆、还是缓存 token 之类的等等,都可以通过配置文件和中间件随意切换,不需要改动一行业务代码,这不是更简单了吗?而登陆到底是要用 session 还是 auth2,这个可以交给“核心工程师”去实现。

    而且不仅如此,laravel 的几乎所有组件都是这样的模式,系统把大部分功能都抽象成了一个统一的简单易用的功能接口,“应用工程师”写业务代码并不需要关心这些功能的具体实现,只需要简单的调用数行代码就行,可以把专注点放在业务上,而这些底层组件可以采用第三方扩展包也可以由“核心工程师”自己编写,然后通过配置文件切换而不用影响业务代码。

    你所考虑的,laravel 早就想到了。

  • 主 資深大佬 : dvaknheo

    @jqh 这是一个例子恰好演示了其糟糕性。
    单是返回就有四种可能

    return $this->error($vaptcha->getError());
    return $this->validationErrorsResponse($validator);
    return $this->sendLoginResponse($request);
    return $this->validationErrorsResponse([$this->username() => $this->getFailedLoginMessage(),]);

    而且注意到的是,按常理,最后一个才是正常返回。取反放最后就是。
    但是这样还没完。
    validationErrorsResponse 接受的参数又是 Validator ,又是 array 。还好 php 是弱类型。
    可是 $this->getFailedLoginMessage() 又从哪里来? 是否前面的调用会影响状态。
    $this->guard()->attempt($credentials, $remember)

    这个 guard() 也是怎么冒出来的,为什么要和控制器耦合,这个 attepm 词也很少见。
    为什么不是 this->attempt($credentials, $remember)

    下面是我重构的结果。

    “`
    class MyController
    {
    public function postLogin(Request $request)
    {
    // 输入处理,放前面,不必节省性能。
    $remember = (bool) $request->input(‘remember’, false);
    $credentials = $request->only([$key_username, ‘password’]);
    //这也算输入吧
    $key_username= $this->username();

    //验证码服务
    $error = VaptchaService::make()->validate();
    if ($error) {
    // 验证不通过
    return $this->error($error);
    }

    //兼容,如果 service 有方式获得这个 $guard,则不需要输入。
    $guard = $this->guard();

    //登录服务
    $error = LoginService::make()->login($guard,$key_username,$credentials,$remeber);

    if($error){
    if(is_array($error)){
    $error[$key_username] = $this->getFailedLoginMessage();
    }
    return $this->validationErrorsResponse($error);
    }
    return $this->sendLoginResponse($request);
    }
    }
    class VaptchaService
    {
    // 省略 make 静态方法。
    public function validate()
    {
    // 验证验证码是否正确
    if (! Vaptcha::make()->validate()) {
    return $vaptcha->getError();
    }
    return null;
    }
    }
    class LoginService
    {
    // 省略 make 静态方法
    public function login($guard,$key_username,$credentials,$remember)
    {
    // 验证参数
    $validator = Validator::make($credentials, [
    $key_username => ‘required’,
    ‘password’ => ‘required’,
    ]);
    if ($validator->fails()) {
    return $validator;
    }
    // 登录验证
    $flag=$guard->attempt($credentials, $remember);
    if (!$flag) {
    return [ $key_username => “something wrong”];
    }
    return null;
    }
    }
    “`

    如果使用 DuckPhp 你大概会这么写。

    “`
    class MyController
    {
    // 登录页面
    public function login()
    {
    C::Show([],’login’);
    }
    //处理 post
    public function do_login()
    {
    // 输入处理,放前面,不必节省性能。
    $remember = (bool) C::POST(‘remember’, false);
    $credentials = C::SG()->_POST();

    $error=null;
    try{
    //验证码服务
    VaptchaService::G()->validate();
    //登录服务,返回用户信息。
    $info = LoginService::G()->login($credentials,$remeber);
    //保存 session 数据
    SessionService::G()->setLoginUserInfo($info);

    C::Show(get_defined_vars(),’login-done’);
    }catch(Throwable $ex){
    $error = $ex->getMessage();
    C::Show(get_defined_vars(),’login’);
    }
    }
    }
    “`
    为什么要调 3 个服务解决问题,而不是一个,
    第一个是处理验证码的,和 web 平台有关的特殊服务
    第二个是主要业务,测试的时候,可以命令行运行,获得信息,不必通过 web
    第三个是 session 系统管理,管控所有 session 系统,也是和 web 平台有关的特殊服务

  • 資深大佬 : jqh

    @dvaknheo 你暴露了,就凭你不知道 guard 和 attempt 方法还说自己弄懂了 laravel auth….,guard 和 attempt 就是 auth 的组成部分。

  • 資深大佬 : jqh

    return $this->error($vaptcha->getError());
    return $this->validationErrorsResponse($validator);
    return $this->sendLoginResponse($request);
    return $this->validationErrorsResponse([$this->username() => $this->getFailedLoginMessage(),]);

    这些只是响应数据的方法,没必要展示出来而已。

    而你这些 service 只是业务代码的结构约定划分,跟框架没有半毛钱关系,我如果愿意也可以这样划分。而你这个 sessionservice 就是画蛇添足,使用了 laravel auth,业务层根本不必关心登陆验证是要使用 session 还是 token,这些根本不必跟业务代码耦合。

  • 主 資深大佬 : dvaknheo

    @jqh 问题是为什么一个简单的登录,会搞出那么多东西出来? 真的会有人重写这个 guard 的实现么?
    控制器的 $this->guard() 要查找多少代码理解。这也就是 Laravel 不能用 类名 /方法 文件路由的原因。
    我刚才查了手头的 laravel 6 的 例子,没找到你这段代码,不知道你这是 laravel 几的版本。

    业务层必须能用命令行运行,最好是无状态的。Web 控制器层不做业务。 控制器不能 dump 起来一堆方法都不知道干什么的。

    不要指望应用工程师通读了 IlluminateAuth 和 IlluminateFoundationAuth 之后才开始工作。

  • 資深大佬 : love51money

    关注。主辛苦。

  • 資深大佬 : yxn1910

    我一直有个很巨大的疑问,都已经用上 laravel 的人,相比于直接上 spring boot 有哪些非用不可的理由?
    1.相较其他框架更大开发效率?
    2.相较其他框架更快代码执行效率?
    3.巨大的投入产出比?
    4.投入时间进行学习后更利于找到工作?
    5.更加优雅?

  • 資深大佬 : DavidNineRoc

    @yxn1910
    你说的都没用,最直接的公司用 PHP

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具