V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  dvaknheo  ›  全部回复第 7 页 / 共 14 页
回复总数  270
1  2  3  4  5  6  7  8  9  10 ... 14  
2020-05-19 20:49:53 +08:00
回复了 timqian 创建的主题 程序员 我的一年独立开发经历
推广比代码难多了。我自己的感觉
2020-05-17 15:05:19 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@jqh 问题是为什么一个简单的登录,会搞出那么多东西出来? 真的会有人重写这个 guard 的实现么?
控制器的 $this->guard() 要查找多少代码理解。这也就是 Laravel 不能用 类名 /方法 文件路由的原因。
我刚才查了手头的 laravel 6 的 例子,没找到你这段代码,不知道你这是 laravel 几的版本。

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

不要指望应用工程师通读了 Illuminate\Auth 和 Illuminate\Foundation\Auth 之后才开始工作。
2020-05-17 14:02:54 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@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 平台有关的特殊服务
2020-05-17 11:33:29 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@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 程序员。
2020-05-16 23:10:07 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
DuckPhp 1.2.3 到 1.2.4 版本有个显著改变是之前组件都没继承基类,实现什么接口。只使用 SingletonEx trait 做可变单例。

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

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

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

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

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

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

最后,还可能会有什么问题呢?
Helper 的函数名字冲突,比如你在旧版本的 Helper 加了个函数, 升级后函数名相同,但签名不同,这也是不太可能出现的情况。
2020-05-16 22:53:29 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@ruoge3s 控制器的构造器就是干这样的活的,还觉得耦合严重。。。
控制器又不需要继承系统基本类,一看就明白。
给你看个耦合严重的控制器例子吧。

```
namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

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

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

keep it simple stupid.
2020-05-16 21:22:36 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@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']['UserSystemDemo\Base\App'] = 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
2020-05-16 21:06:51 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@DavidNineRoc

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

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

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

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

因为我闭门造车,很多小的细节不可避免的有问题,目前就是希望能有一小撮人一起来讨论,做好。
2020-05-16 18:27:40 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@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 也有些地方,总感觉可以做得更好,但是总是缺一个人提醒一下。
2020-05-16 17:15:00 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@iidestiny
Laravel 不能节省运行效率和开发效率。 违背了 PHP 简洁之道。

随手举例子

+ blade 模板 违背了 PHP 代码就是视图的原则
+ 滥用 ArrayIterator foreach, 使得没法 dump
+ orm 使得调试更麻烦了
+ 退化到路由表了。有简单的文件路由不用。
+ 中间件使得调用关系复杂化。
2020-05-16 13:21:29 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@littleylv .php_cs 文件, 就额外几条规则。你这里说的,没用 php-cs-fixer fix 检查出来。

```
<?php
$header = <<<'EOF'
DuckPhp
From this time, you never be alone~
EOF;
$finder = PhpCsFixer\Finder::create()
->files()
->in(__DIR__.'/src')
->name('*.php')
;
return PhpCsFixer\Config::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 群里讨论
2020-05-16 13:10:55 +08:00
回复了 dvaknheo 创建的主题 PHP DuckPhp 1.2.4 发布,终极架构,文档完善了
@littleylv 我系统命名空间是用 DuckPhp,所以统一成 DuckPhp 。 要不,还得把命名空间全调整成 DuckPHP ?


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

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

是有自动加自的。

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


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

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

再说了别人有 bug,你自己造的轮子也有可能有 bug 呀
////
所以现代框架就必须要有出 Bug 的时候可以不硬改系统代码,在工程里改正的方法啊。
写业务来不及写。清理测试还折腾。虽然提炼出业务层后,内部测试方便多了。
不过写 DuckPhp 框架的时候,我做了 100% 覆盖测试。
覆盖测试比单元测试有意义吧。
2020-05-14 22:01:37 +08:00
回复了 kaygb 创建的主题 PHP 分享自己写的 typecho 主题——WINDS
顺路看了一下 typecho 的代码。和 wordpress 类似,都还是在中古时期。

毕竟不是每个虚拟主机都能上 php 7.2 的。

23559 行 php 代码,要写的话也要花很长时间才能搞定。

最难看的部分是 Widget,其他还好办.
2020-05-10 22:27:36 +08:00
回复了 imme90 创建的主题 程序员 前端和 UI 设计是否真的一文不值?
@imme90 现在的 PHP 程序员还会 es6 之前的 js 么?
我也有过,这么简单的 js,还是我来写吧,这种时候。
所以不明白老板招那些前端来干什么
2020-05-10 22:12:40 +08:00
回复了 imme90 创建的主题 程序员 前端和 UI 设计是否真的一文不值?
当年怎么做的? 画图切图,静态页面是一个人负责。JS,PHP 数据库是另一个人负责,甲方画个原型图。到现在包小项目也是这么来的。
现在画图的, 一个人, 切图仔切图,写 JS 。PHP 少干了活。 对了,还有产品 也过来分钱了。

画图,切图,配色, 不应该由一个人来搞定么?考核水平就是静态页面好不好看——这是艺术家 ,话说应该怎么给这些艺术家算工资?

有这么多项目需要用到 超级复杂的 js 么? ——当然,你要是自己弄播放器,那还是单独前端吧。这活承认比写后端的难,工资多大家服。
2020-04-29 18:06:40 +08:00
回复了 dvaknheo 创建的主题 PHP [吐槽]刚读了 yii3-demo, PHP 框架是怎么把 PHP (优雅的)玩死的。
我 fork 了一个 yii3 demo 的版本(大概 80%进度),在 入口处 加了些代码,强行插入 duckphp 框架版本的实现。见

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

我切 github 默认分支不是 master 分支,而是 for_duckphp 分支。

for_duckphp 分支,实际干了两个分支的事情,后面再拆分。

for_duckphp 另一个分支功能的事情 是 service 化。src/service 目录 ,抽出来,单独成立一个分支,然后画关系图让大家看看 这部分和 duckphp 没关系

最主要的就是在 index.php 入口 插入 duckphp 版本的实现。
duckphp 版本的特点

1. 只在 composer.json 依赖一个包:dvaknheo/duckphp 1.2.3 。
2. 相关实现都在 app 目录底下。其他文件只改了 public/index.php ,src/Command 目录的命令行入口。
3. 保证输出和 yii3 demo 一致。原有 bug 不改。入口文件在请求完之后 curl 原来 url,如果相同输出,则输出 same. 否则输出 different 并在 runtime 里加 a.php ,b.php 方便对比。
4. 业务逻辑提取成 Service 层 . 6 个目录,view 是视图目录,config 是配置目录, Model 跟着 表走,Controller 负责输入,输出 view 前处理,业务放到 Service 。 Base 目录是核心才动的目录。基本上不交叉引用。

用 cloc 算了一下 app 目录 1760 行,比 src 目录 2289 行少点, 还有点 yii 的引用,主要是 3 个复杂组件没拆解,也不想拆解,留着就行。 分页还有进一步调整可能。

两个星期折腾这个代码,感觉有点慢。 或许,就弄了个大白象?
回头来看 yii2 的代码主要还是 卡在 behaviors 和 actions 上, 说不定哪天就重写了。 然后把 gii 也重写了。

到现在,逆行工程,主要还是,这玩意从哪里来的? 这玩意被什么东西悄悄调用? 这玩意里面有什么?

yii3 里 那个 widget PostCard 在 view 里计算 我就很不爽, 后面拆解成 view 文件 ,传入 array 。看上去清晰多了。

还有想吐槽的暂时记不清,就暂时到这吧。
2020-04-15 22:48:13 +08:00
回复了 dvaknheo 创建的主题 PHP [吐槽]刚读了 yii3-demo, PHP 框架是怎么把 PHP (优雅的)玩死的。
额,我自己失误了,G() 函数确实会在业务中用到。如果为了扩展性。
XService::G()->foo 和 XModel::G()->foo 这种用法经常有。
或许实践起来会有一排,改成 static function 调用 吧,就是
XService::foo(); 和 XModel::foo();

有一种情况是 XSerivce::G 这模式省不了, 没默认载入的扩展,JsonRpcExt 切换成远过程调用。这属于高级用法了,具体在相关 ref 里
2020-04-15 21:40:34 +08:00
回复了 dvaknheo 创建的主题 PHP [吐槽]刚读了 yii3-demo, PHP 框架是怎么把 PHP (优雅的)玩死的。
@JokeEnd
App::G 又不是给写业务代码的用的,业务代码的人,一般只会在 Controller, Service,Model,View, 这四个目录。对应的 ControllerHelper,ServiceHelper,ModelHelper,ViewHelper 里有什么东西才值得看。 这些 Helper 的 GetExtendStaticMethodList() 有点恶心而已。

G 方法用于扩展的。 比如你要替换默认的实现。

@zencoding

奇怪,怎么不从主流程看起呢? RouteHookRewrite 这个扩展默认没加载,而且我文档都没写完啊。
如果你从代码琢磨起。 最古怪的是怎么 DuckPhp\App 初始化后跑的是 MY\Base\App 的代码。这部分需要在 init 函数里琢磨一下。

DuckPhp\Core\App use DuckPhp\Core\Kernel->init ,run 才是核心, 还有个复杂的是 DuckPhp\Core\Route 路由。

@jhdxr
字符串拼接效率高,有数量级上的差距。
谢谢,我之前没估计过。,但 View 还是基本上以 echo 方式显示的,基本没见到 heredoc 类型的。如果追求效率,看来还是把 view 文件转为 heredoc 模式的文件好,综合起来,这为方便牺牲效率,这可以接受。
2020-04-15 10:59:08 +08:00
回复了 dvaknheo 创建的主题 PHP [吐槽]刚读了 yii3-demo, PHP 框架是怎么把 PHP (优雅的)玩死的。
@jhdxr 恕我浅薄,我真不知道依赖注入,对于动态语言,除了解决 [调用方式不变,实际实现可变] 功能之外还能有什么用。

各 php 框架内部不用 ob 系列方法实现么?超长字符串拼接效率高还是 ob 函数分段输出效率高?

我所说的热修复,就是不强行去改第三方库的代码,修复出第三方库出现的功能。

就是要跟踪到第三方库还没解决问题,这才是折腾。

第三方 lib 能学用当然用。吐槽的是 framework .
1  2  3  4  5  6  7  8  9  10 ... 14  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2825 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 21ms · UTC 14:15 · PVG 22:15 · LAX 06:15 · JFK 09:15
Developed with CodeLauncher
♥ Do have faith in what you're doing.