Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

:let套太多层,会造成一些类型是对象的变量丢失 #55

Open
lyt9304 opened this issue May 31, 2016 · 14 comments
Open

:let套太多层,会造成一些类型是对象的变量丢失 #55

lyt9304 opened this issue May 31, 2016 · 14 comments
Labels

Comments

@lyt9304
Copy link

lyt9304 commented May 31, 2016

::div.test (regularPosts, vipDingPosts)
    :let a = *[0], a2 = *[1]
        - echo $a->count();//输出5
        - echo $a2->count();//输出4
            :let b = 1
                - echo $a->count();//应该输出5,但是报错Undefined Variable a
                - echo $a2->count();//应该输出4,但是报错Undefined Variable a2

当mixin的参数是对象,并且嵌套2层以上:let就会造成变量丢失,但是普通的字符串或者数字不会丢失。

::div.test (regularPosts, vipDingPosts)
    :let a = *[0], a2 = *[1]
        - echo $a->count();//输出5
        - echo $a2->count();//输出4
            :let b = 1, a = a, a2 = a2
                - echo $a->count();//输出5
                - echo $a2->count();//输出4

要这样中继一下,才可以在下面读取到。

@hax
Copy link
Contributor

hax commented May 31, 2016

won't fix
这跟:let层次没有直接关系,只是因为每层缩进需要转换为php的closure,从而需要在use语句里指定用到的外层变量,但是jedi并不会分析-内嵌的php代码里对外部的引用。

  1. - 里的代码对外层变量的引用是无法处理的,除非parse PHP代码,但这个事情很麻烦又没有什么价值。
  2. 这里完全可以用内建方式,没有必要用 -
  3. - 的缩进层次没有必要。

建议代码写成这样:

::div.test (regularPosts, vipDingPosts)
    :let a = *[0], a2 = *[1]
        = a.count()
        = a2.count()
        :let b = 1
          = a.count()
          = a2.count()

@hax hax closed this as completed May 31, 2016
@hax hax added the wontfix label May 31, 2016
@lyt9304
Copy link
Author

lyt9304 commented May 31, 2016

业务逻辑中可能是通过植入php代码去获取一些值不是纯展示的,比如

- $superPostsCount = ($spbiddingPosts && $topPosts && $pinnedPosts) ? ($spbiddingPosts->count() + $topPosts->count() + $pinnedPosts->count()) : 0;

如果把这部分提前也是可取的,但是有时候前后隔太远,可读性就差了点

:let分层的一部分原因是因为必须要写在一行里,有时候实在是需要处理的太多了才分成了2层,不知道jedi中有没有什么比较好的处理方式

:let regularPosts = *[0], spbiddingPosts = *[1], topPosts = *[2], pinnedPosts = *[3], cpmPosts = *[4], bdPosts = *[5], searchPromotePosts = *[6], cpcPosts = *[7], vipDingPosts = *[8]
        :let i = 0, siteType = if city then city.type, hideAddress = siteType == Area.TYPE_CHINA || siteType == Area.TYPE_PROVINCE

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented May 31, 2016

这是bug
let的语句并不在php的插值里,应该被解析并加到,应该默认给后面的let用到

如果不修的话,会导致非常难和工程师说明这个规则.记忆的成本也会非常大.
比方这个issue本身就是最好的例子,"嵌套太多层"到底是什么意思? 要推广给工程师说
"jedi里如果有多层let嵌套,第一层声明的变量,在第二层声明的变量作用域的php echo 插值是不可用的"
就太困难了.

此外issue里的例子是contrived,实际viewad和listing里php套插值的多了去了,根本不可能用内带的函数完成

@hax
Copy link
Contributor

hax commented May 31, 2016

计划会支持非嵌套的 let 语句。(但需要一定时间,因为需要完全重构目前binding的实现方式。)

但嵌套 let 本身目前的实现并没有bug。在上面的例子里,只要不是-里使用,是可以正常引用的。
- 本来就是一个后门,并对同构是个障碍,早晚要去掉。

现在绝大部分地方的-使用都是没有必要的(毛估估80%以上)。其次滥用-实际导致业务逻辑侵入到了表现层。

一行写不下的表达式90%的可能是,那是业务逻辑。本来就不应该塞到模板里。

如果有强烈的需求要在模板里写业务逻辑,则需要用其他方法支持,比如加入函数。但肯定不是现在这样。

@HerringtonDarkholme
Copy link
Contributor

如果有强烈的需求要在模板里写业务逻辑,则需要用其他方法支持,比如加入函数。但肯定不是现在这样。

这不切实际。
就目前而言没地方放函数也就算了,就算有函数也一样坑。有大量小逻辑难以用jedi表示
或者可以表示,因为诡异的let需要缩进很多层。

如果觉得可以不使用 -,那么改正listing.jedi,我不信listing.jedi可以不用-

@lyt9304
Copy link
Author

lyt9304 commented Jun 1, 2016

现在有很麻烦的事情就是,有些mixin参数太多了,但是jedi又不支持直接使用参数,一定要使用:let接受遍参数

::ul.list.multiplex (regularPosts, spbiddingPosts, topPosts, pinnedPosts, cpmPosts, bdPosts, searchPromotePosts, cpcPosts, vipDingPosts)
    :let regularPosts = *[0], spbiddingPosts = *[1], topPosts = *[2], pinnedPosts = *[3], cpmPosts = *[4], bdPosts = *[5], searchPromotePosts = *[6], cpcPosts = *[7], vipDingPosts = *[8]

比如以上这个例子,参数有九个,都用let接受一遍一行就很长很长了,别的逻辑只能放到下一层

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Jun 1, 2016

我觉得let就不应该多一层嵌套
缩进本来是用在表示html层级的
现在:let的嵌套又多了一层变量scope的职责,不代表html层级
还不如两者统一,html层级就代表变量scope

一般编程语言或者模板引擎里也不会声明变量就要多缩进啊

于是上面let太长的问题就完全可以写多行而不蛋疼

@hax
Copy link
Contributor

hax commented Jun 1, 2016

@lyt9304 上面这个代码建议改成这样:

:: ul.list.multiplex ()
  :let model = *
    // 下面可直接用 model.regularPosts ... 等

等将来完全支持解构后,可改为

:: ul.list.multiplex {regularPosts, spbiddingPosts, topPosts, ...}
  // 下面可直接用 regularPosts ... 等

@hax
Copy link
Contributor

hax commented Jun 1, 2016

@HerringtonDarkholme 前面的comment说了:

计划会支持非嵌套的 let 语句。(但需要一定时间,因为需要完全重构目前binding的实现方式。)

另外,嵌套的let是有用的,比如rust/swift的 if let 构造。

@hax
Copy link
Contributor

hax commented Jun 1, 2016

@HerringtonDarkholme

有大量小逻辑难以用jedi表示

需要cases。然后我会考虑解决。

以下是已知的问题:

  1. php namespace(开发中)
  2. 循环计数(开发中)

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Jun 1, 2016

好吧,我看了一下现在的php插值,基本是这么几类

  1. namespace
  2. 循环结构里的index
  3. 避免external
  4. break
  5. 赋值
  6. 避免let缩进
  7. new Class

如果都能修掉的话,估计是有80%的php代码能干掉
我还是觉得call_user_func_array的写法可以避免

@hax
Copy link
Contributor

hax commented Jun 1, 2016

1、2、6 都在开发中。
3 的原因是?
4 的具体case?
5 一般的用let就可以了。reassign/rebind/mutate一开始就是要禁止的。如果有不满足的需求,case by case我看。
7 在模板里创建新的功能对象通常是业务逻辑入侵的结果。即使真有这样的需求,很容易在php层面加个factory。

@HerringtonDarkholme
Copy link
Contributor

3的原因就是开发者不愿意在外面多写一个external。那个时代jedi有bug
4的break大师兄你自己搜就知道了

@hax
Copy link
Contributor

hax commented Jun 2, 2016

嗯,看来我最好给所有 - 都扔个 warning...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants