作者归档:admin

Yii 框架的视图层实现

如果你想看看 Yii 框架的视图实现过程,请继续向下;如果你想看看胖子的碎碎念,请直接拉到文章最后;如果你只是路过,那也路过留名吧^_^。

Martin Flower 在《企业应用架构模式》中提到 MVC 模式的关键点在于两个分离:从模型中分离视图和从视图中分离控制器。视图的表现在很大程度上决定了此模式的使用,以及框架对 MVC 模式的各个层级的分离水平。 Yii 框架是一个基于 MVC 模式的框架,它在视图这块做了很多的工作,很清晰的实现了视图的功能。

Yii 框架的视图是一个包含了主要的用户交互元素的 PHP 脚本。每个视图有一个名字,当渲染( render )时,名字会被用于识别视图脚本文件。视图的名称与其视图脚本名称是一样的。例如:视图 edit 的名称出自一个名为 edit.php 的脚本文件。要渲染时,需通过传递视图的名称调用 CController::render()。这个方法将在 “protected/views/控制器 ID” 目录下寻找对应的视图文件,其寻找方法为 getViewFile。这里的 protected/views 只是默认的存储位置,我们可以通过 Yii::app()->setViewPath 方法改变此路径。

在视图脚本内部,我们可以通过 $this 来访问控制器实例。同时,我们也可以在视图里以“$this->属性名”的方式获取控制器的任何属性,这种调用方式是通过实现__get魔法方法实现的。

一次较为完整的视图渲染过程在 CController 类的 render 函数中体现得淋漓尽致。当控制器中从模型(model)中拿到数据后,一般会执行 render() 方法创建视图,其大概过程如下:

  1. 执行预留的 beforeRender 钩子。
  2. 查找渲染局部内容 $output,实际上这里是一个部分视图渲染的过程,它包括获取视图文件路径,渲染视图文件,处理输出三个部分。在渲染的过程中,通过 PHP 中的 extract() 方法把数组中将变量导入到当前的符号表,直接 require 视图文件,从而合并数据和表现。
  3. 如果存在布局,则将得到的内容放入以 content 为下标的的数组传递给父类的 renderFile() 方法中,重复执行渲染视图的过程。在布局中执行 ,输出局部内容$output,实现了局部和布局视图的合并。为了实现多级布局,在布局中还可以通过控制器的视图装饰方法加载。
  4. 执行预留的 afterRender 钩子。

在渲染视图的时候,如果参数中有传递对应的值,会执行 processOutput() 方法,此方法一般在渲染视图结束时才会调用,它实现了三个过程:

  1. 注册客户端脚本,具体由 ClientScript 组件管理。
  2. 如果存在,则执行动态内容输出。
  3. 页面内容 base64_encode 加密,如果存在 zlib 扩展,则会先压缩。

在 CController 类中对视图的渲染除了上面的render方法外,还有其它多种方法:

  • render方法: 和布局一起渲染 render($view,$data=null,$return=false)
  • renderPartial方法: 仅渲染视图内容,或者是渲染部分页面内容。它与 render() 方法的不同是它不会渲染布局,并且在 render() 方法中也会调用此方法。 renderPartial($view,$data=null,$return=false,$processOutput=false)
  • renderText方法:渲染静态内容和布局。renderText($text,$return=false)
  • renderDynamic方法:通过回调函数渲染动态内容,通常我们会在模板文件中中调用此方法。renderDynamic($callback)->renderDynamicInternal($callback,$params)
  • renderClip方法:渲染显示 CClipWidget 生成的内容,此处需要指定名字。renderClip($name,$params=array(),$return=false)

对于不同的页面中共用的内容,虽然可以通过 renderPartial 方法渲染部分页面视图,但是必然存在对于数据部分的重复,因为这些视图都需要调用控制提供的数据,从而产生耦合。因此 Yii 框架 提供了另一个独立的视图部件,官方称之为 Widget (小物件?小挂件?)。

小物件是 CWidget 或其子类的实例。它是一个主要用于表现数据的组件。小物件通常内嵌于一个视图来产生一些复杂而独立的用户界面。也算是一种界面的独立和松耦合的设计。如我们做WEB应用时常用的列表,翻页,日历等。这些 Widget 增加了界面的复用度,减少了代码量。

与前面视图部分不同的是,它没有布局文件支持,并且 Widget 视图中的 $this 指向 Widget 实例而不是控制器实例,这里实现了与控制器的分离。如果要实现一个自定义的 Widget ,我们仅需要继承 CWidget 并覆盖其 init() 和 run() 方法,可以定义一个新的 Widget 。

我们在视图中通过 $this->widget() 或 $this->beginWidget() 和 $this->endWidget() 调用 Widget,两者的区别在于第二个方法可以在显示的过程中添加 html 内容。添加内容的位置在 init() 方法和 run() 方法输出的内容之间。

除了布局、Widget 外, Yii 框架实现系统级的视图,用来显示 Yii 的错误和日志信息。

系统视图的命名遵从了一些规则。比如像“errorXXX”这样的名称就是用于渲染展示错误号 XXX 的 CHttpException 的视图。在 framework/views 下, Yii 提供了一系列默认的系统视图. 我们可以通过在 protected/views/system 下创建同名视图文件进行自定义。系统默认的 exception 视图非常赞,结合 Yii 本身的 traces 机制,当抛出异常或出错时就会很详细的定位出问题的代码所在。

以上只是胖子阅读 Yii 框架源码的笔记。结合《企业应用架构模式》这本书的内容,如页面控制器、前端控制器、活动记录等,胖子发现对框架的实现有更深入的理解。一方面印证了书上的理论,一方面为实现过程的原理找到了出处。不晓得 Yii 框架的作者是否对此书也有精读,或者是经验的积累?

参考资料: http://www.yiiframework.com/doc/guide/1.1/en/basics.view

PHP的ticks机制

PHP的ticks机制

要过年了,在年前完成这篇文章,如果有缘可以看到,祝福看到的朋友新年快乐,在新的一年里,万事顺意!

按今年的计划每个月至少有两篇文章,而一月份因为各种理由而只有一篇2012的总结,无论什么原因,总归是不对的。这篇算是补上的,也作为今年的开始。

回正题,今天要研究的是PHP的ticks机制。

PHP提供declare关键字和ticks关键字来声明ticks机制。如:declare(ticks = N); 这表示:在当前scope内,每执行N句internal statements(opcodes),就会中断当前的业务语句,去执行通过register_tick_function注册的函数(如果存在的话),然后再继续之前的代码。需要注意的是这里的N是指的PHP的一些OPCODE,而OPCODE与我们见到的PHP语句却不是一一对应的。

最开始我以为PHP内核是在编译时记录是否有ticks机制,在真正执行中间代码时插入判断代码,实现此机制。但是事实上却不是这样滴。

看PHP代码示例1:

    $name = "phppan";
    echo $name;
    class Tipi {
        public function test() {
            echo "test";
        }
    }
    function f_tipi() {
    }

如上代码包括了我们常见的几种语句,赋值,输出,定义类,定义函数。通常我们用VLD查看PHP生成的中间代码,上面的代码通过 php -dvld.active=1 t.php 我们会看到 ECHO、ASSIGN、NOP等中间代码。

现在我们在示例1的代码上添加上ticks机制。如PHP代码示例2:

    declare(ticks=1);
    $name = "phppan";
    echo $name;
    class Tipi {
        public function test() {
            echo "test";
        }
    }
    function f_tipi() {
    }

示例2与示例1相比也就是多了第一条语句: declare(ticks=1); 如果我们此时再次通过VLD查看中间代码,会发现在每个中间代码的后面都多了一句中间代码:TICKS

是否因为ticks=1的原因而在每个中间代码的后面添加了TICKS?将declare(ticks=1);换成declare(ticks=100);,再次VLD,结果没有变化。从以上的结果可以看出,PHP内核在语法分析过程中实现了ticks机制。

从实现过程来说定义ticks机制分为两个过程:一个是定义是否需要执行ticks或者说声明ticks机制,另一个实现在声明了ticks机制的情况下控制语句的执行。

声明ticks机制过程

声明的过程就是调用declare(ticks = N); 在语法分析时根据declare关键字和参数中的ticks关键字来声明ticks机制。通过zend_compile.c文件中的zend_do_declare_begin、declare_statement、zend_do_declare_end三个函数来编译声明ticks机制。在declare_statement函数中我们可以看到:declare除了可以声明ticks之外,还可以声明encoding,这在代码里面就是一个if else的判断。

ticks机制的声明仅在编译过程有用,它为后面的声明控制语句服务。其编译过程中的全局变量为:CG(declarables)。这是一个结构体,它仅有一个成员:ticks。当然后面应该还会有更多的成员出现。

声明控制语句

示例1和示例2已经充分说明在每条语句的语法分析时,会根据是否声明了ticks机制来添加TICKS中间代码,其实现在于每条语句在语法解析时都会添加一条函数调用:zend_do_ticks。从zend_language_parser.y文件中可以看出:zend_do_ticks函数添加在类定义语句,函数定义语句和常规语句的后面。 zend_compile.c文件中的zend_do_ticks函数会根据前面提到的 CG(declarables).ticks 来判断是否生成 ZEND_TICKS 中间代码(在VLD中看到的中间代码都是没有ZEND开头)。

除了声明ticks机制,还有执行。执行过程中关键的变量是在声明时的ticks=N。其实这里的N可以换个角度去理解:ticks指定的数字是指执行了多少次TICKS语句。在TICKS中间代码的执行函数ZEND_TICKS_SPEC_CONST_HANDLER中,会统计执行当前函数的次数,存储变量为EG(ticks_count)。当达到当初声明的界限,就会调用一次所有通过register_tick_function注册的函数,并计数清零。

与当初自己设想的实现相比,PHP内核对ticks机制的实现满足了功能单一原则和松耦合原则。将ticks机制作为一个中间代码添加到整个中间代码的执行体系中,包括状态的转移,函数的切换这些都是直接使用原有的机制。

ticks机制的应用场景

手册上说:Ticks 很适合用来做调试,以及实现简单的多任务,后台 I/O 和很多其它任务。

在调试过程中,对于定位一段特定代码中速度慢的语句比较有用,我们可以每执行两条低级语句就记录一次时间。虽然这个过程也可以用其它方法完成,但用 tick 更方便也更容易实现。

PCNTL也使用ticks机制来作为信号处理机制(signal handle callback mechanism),可以最小程度地降低处理异步事件时的负载。这里的关键在于PCNTL扩展的模块初始化函数(PHP_MINIT_FUNCTION(pcntl))。在此模块做模块初始化时,它会调用: php_add_tick_function(pcntl_signal_dispatch);将pcntl的分发执行函数添加到ticks机制的调用函数中去,从而当ticks触发时就会调用PCNTL扩展函数中指定的所有方法。

2012年度总结

在2011年的年度总结有说过:“以前没有写总结的习惯,那么从2011开始吧。”,今天算是第二年了。时间真的是把杀刀,咔咔的就过去了,带过了即将结束的青春的尾巴,也许明年就不能过青年节了。

一、2012年总结

1、2012计划实现情况

<< 2011年度总结 >> 总结中,有量化2012的计划:

2012,给个量化的值吧。
1、读书:10+技术书,30+非技术且不含小说
2、工作:把没有实现的那2个想法实现,参与开发,每周至少一个工作日在编码。
3、生活:把1件大事给办了。
4、TIPI;发布3章+

第1项完成,还有多的,虽然看的书比较扯淡。技术没有明显进步,还是局限在一个小地方打转。没有深度和广度的探究,轻慢了,唉。第2项只能算是基本完成,想法实现了大半,又有了新的想法,只是不晓得有没有机会去实现了。坚持在工作中参与编码,有时却有些力不从心,打断太多,事儿太杂,也该理理了。第3项圆满完成,虽然过程中有些小波澜,但是结果是好的。第4项貌似没有完成……

2、关于生活

对于我来说,2012是一个很忙的年份,在深圳买了房子,算是深圳人了,在深圳结婚了,后代也算是深圳人了,也许这根就留在深圳了。

深圳的房子贵,关内 2万+ 一平的房子,2个月看了不下30间,有那么一两间合适的,还巨贵。算了,和媳妇商量着是不是去关外买一个。在关外看了两间,都是小复式,都挺喜欢的,于是在5月1号劳动节之前的那个晚上就定了。到年底,到手的小窝总价涨了10多万,直叹媳妇决策英明。给自己住的,也没有太多的讲究,到时候简单买些家具,布置下,这事就算是完了。

结婚。嗯,现在是已婚人士了。
求婚策划了好久,不过因为没有经验,也没有给媳妇买过戒指,在晚上量媳妇手指大小时把媳妇给弄醒了,于是这事就给让她知道了,但是打死也不透露具体时间。终于在其好友的帮忙下,把她约出去后,在家里客厅详细布置了一番,才求婚成功,算是有点惊喜。比较纠结的是在求婚的时候嘴巴还是歪着的。

说完喜事,得说点纠结的事,在<< 那段不堪回首的日子 >> 记录中,已经说过了,这事影响了求婚,影响了结婚,也影响了工作,因为每天都需要请假做冶疗。

这一年基本就三件大事了。

3、关于工作

在5月份因为某些事情写了篇 << 转岗一年总结 >>,这里算是其延续。虽然拉长整个时间轴会发现遇到的困难都不算困难,因为一切都会过去。老大换了一个部门,我也换了一个老大,不晓得将来会是怎样,只是还在那里坚持,不知道是为了什么而坚持。忙,盲,茫?

这一年以来,明显感觉到自己成长了,不再是那个只会编码的程序员了,一些新的认识如下:
(1)对技术管理有了一点新的认识。
技术管理管的技术,管的是技术能力,管的是项目开发。技术是指你所领导的团队的技术规划,正在使用的技术的优化,正在运行的架构调优等。技术能力是指团队成员的技术能力,技术管理更多的是关注成员的技术成长,为其规划成长路线。项目开发是指实际项目过程中对项目采用的技术进行审核,跟进开发过程。
(2)对编程和技术管理的关系的重新认识。
做技术管理需要编程,但不能全部投入到编程中,只能有大概10%到20%的时间在编程上。如果投入时间过多,其结果是你所参与的项目延期,部门工作混乱。并且参与的编程工作尽量不是那种与项目相关,不能让其它人的任务依赖于你的任务。可以是预研性质的代码,或改BUG性质的。
(3)开始学会从更高的层面或不同的角度去看问题。
看问题不能局限于自己的一亩三分地,需要从小部门或大部分,甚至整个公司去考虑某个项目的必要性。老大一直强调要有产品经理的思维,有些许改进,却不甚理想。

还存在问题的地方:
(1)识人的能力
这一年招聘了一些人,有些人还在试用期就走了,什么原因呢?没有想清楚需要的是什么样的人。黄叔说:“交友须胜己,似我不如无”,是要一个技术厉害的,还是一个合适的,技术一般的。能力,态度,孰重?孰轻?可能有人能说会道,实际能力并没有嘴巴厉害;可能有人在面试时态度极好,实际工作态度却大相径庭;如何在面试时把人的能力和态度在一定程度上认清,是一个大的课题。
(2)说话沟通的能力
说话存在两个问题,一个是有时说话声音小,让人听不清,这点我们家领导多次批评了我,却没有明显好转;另一个是在激动时会出现说话中断情况。沟通存在表达的问题,即在表达一个内容时干巴巴的,不够丰满和形象,用一句话来说就是说话太程序员了。
(3)写文档的能力
不管是写WORD,还是写PPT,形式只是外在表现形式,关键是思路。有些东西存在,却无法形成合适的文档表现出来。
(4)技术广度和深度
现在技术到了一个瓶颈点,需要量的积累,这个量不仅仅是知识的量,还有实践的量,另外还需要加强对新知识和新技术的了解和实践。

以上的这些问题都需要时间的积累,在流水的日子里练习,只有不断的练习才会有提高,面试更多的人,多表达,多沟通,多写文档,在这些练习过程中和练习之后,思考你的问题,不断提高。

4、关于学习

读了蛮多书(列表见附录A:2012读书列表),大多不求甚解。读书的目的,一是让自己了解一些经典的东西和一些新的东西,二是让自己养成读书的习惯,三是让自己的思维更系统化。可能读书的ROI不高,却是一个细水长流的活,在将来的某一天你会发现自己的巨大的成长。

TIPI项目在上半还有一些时间兼顾,写了一些东西,却没有太大的改版,也算是去年的遗憾。

二、2013年计划

2013年已经开始了,这三天也狂看书中渡过,算是一个好的开始吧。计划,简单点,量化:

1、过PMP
2、看5+管理 10+技术 10+其它书籍
3、熟悉YII框架的源代码,对其各个模块有清晰的认识(貌似这里没量化了)
4、加强对Linux的认识(量化一些,虐APUE两遍,并结合PHP内核)
5、完成媳妇的两个梦想
6、加强在工作上的掌控力,项目的按时完成率在80%以上。
7、Blog – 平均每月两篇+,这个一直在减少,一部分是觉得写的东西不是自己想要的,有时候文章写了一半,
发现没啥意义,就不写了;一部分是时间更少了,有新的东西需要自己去做。

三、感恩

到感恩环节了。

感谢两边的爸妈,累了半辈子了,养育之恩。感谢一直陪着的兄弟,感谢求婚时帮忙的朋友们,感谢到结婚现场祝福的兄弟姐妹,感谢这一年在我生命中出现的人们,心怀感恩。2013我们还活着。

四、结束语

到这里,应该要写白驹过隙、日月穿梭了。一年就真的过去了,回首望去,荆棘的路上布满了努力 的脚印,新的一年,会有新的开始。

五、附录A 2012读书列表

感谢刀马douban读书列表生成工具