>백엔드 개발 >PHP 튜토리얼 >Yii 프레임워크 소스코드 분석(3)

Yii 프레임워크 소스코드 분석(3)

WBOY
WBOY원래의
2016-08-08 09:33:281209검색

재인쇄 시 표시해 주십시오: TheViper http://www.cnblogs.com/TheViper/

이전 기사에서는 CWebApplication의 \route=$this->getUrlManager ()->parseUrl ($this->getRequest());에 대해 설명했으며 $route=controler/actionid를 얻었습니다.

이 기사에서는 $this->runController($route)에 대해 설명합니다.

<span> 1</span> <?<span>php </span><span> 2</span><span>class</span> CWebApplication <span>extends</span><span> CApplication { </span><span> 3</span><span>public</span><span>$controllerNamespace</span><span>; </span><span> 4</span><span>private</span><span>$_controllerPath</span><span>; </span><span> 5</span><span>private</span><span>$_viewPath</span><span>; </span><span> 6</span><span>private</span><span>$_systemViewPath</span><span>; </span><span> 7</span><span>private</span><span>$_controller</span><span>; </span><span> 8</span><span>public</span><span>$controllerMap</span>=<span>array</span><span>(); </span><span> 9</span><span>public</span><span>function</span> processRequest() {<span>//</span><span>开始执行请求 </span><span>10</span><span> //获取urlManager组件,解析请求,得到controller/action这种格式的string, </span><span>11</span><span> //并且将隐藏参数与请求的参数一一对应,匹配起来,写入$_REQUEST中</span><span>12</span><span>$route</span> = <span>$this</span>->getUrlManager ()->parseUrl (<span>$this</span>-><span>getRequest()); </span><span>13</span><span>$this</span>->runController ( <span>$route</span><span> ); </span><span>14</span><span> } </span><span>15</span><span>public</span><span>function</span> getRequest() {<span>//</span><span>获取request组件</span><span>16</span><span>return</span><span>$this</span>->getComponent ( 'request'<span> ); </span><span>17</span><span> } </span><span>18</span><span>protected</span><span>function</span> registerCoreComponents() {<span>//</span><span>注册核心组件</span><span>19</span> parent::<span>registerCoreComponents (); </span><span>20</span><span> } </span><span>21</span><span>//</span><span>执行contronller</span><span>22</span><span>public</span><span>function</span> runController(<span>$route</span><span>) { </span><span>23</span><span>if</span> ((<span>$ca</span> = <span>$this</span>->createController ( <span>$route</span> )) !== <span>null</span><span>) { </span><span>24</span><span>list</span> ( <span>$controller</span>, <span>$actionID</span> ) = <span>$ca</span><span>; </span><span>25</span><span>$oldController</span> = <span>$this</span>-><span>_controller; </span><span>26</span><span>$this</span>->_controller = <span>$controller</span><span>; </span><span>27</span><span>$controller</span>->init ();<span>//</span><span>钩子,在执行action方法前调用,子类去实现</span><span>28</span><span>$controller</span>->run ( <span>$actionID</span> );<span>//</span><span>开始转入controller类中action方法的执行</span><span>29</span><span>$this</span>->_controller = <span>$oldController</span><span>; </span><span>30</span><span> } </span><span>31</span><span> } </span><span>32</span><span>//</span><span>创建controller类实例,从controller/action这种格式的string中解析出$controller, $actionID </span><span>33</span><span>public</span><span>function</span> createController(<span>$route</span>, <span>$owner</span> = <span>null</span><span>) { </span><span>34</span><span>if</span> (<span>$owner</span> === <span>null</span><span>) </span><span>35</span><span>$owner</span> = <span>$this</span><span>; </span><span>36</span><span>if</span> ((<span>$route</span> = <span>trim</span> ( <span>$route</span>, '/' )) === ''<span>) </span><span>37</span><span>$route</span> = <span>$owner</span>-><span>defaultController; </span><span>38</span><span>39</span><span>$route</span> .= '/'<span>; </span><span>40</span><span>while</span> ( (<span>$pos</span> = <span>strpos</span> ( <span>$route</span>, '/' )) !== <span>false</span><span> ) { </span><span>41</span><span>$id</span> = <span>substr</span> ( <span>$route</span>, 0, <span>$pos</span><span> ); </span><span>42</span><span>if</span> (! <span>preg_match</span> ( '/^\w+$/', <span>$id</span><span> )) </span><span>43</span><span>return</span><span>null</span><span>; </span><span>44</span><span>$id</span> = <span>strtolower</span> ( <span>$id</span><span> ); </span><span>45</span><span>$route</span> = ( <span>string</span> ) <span>substr</span> ( <span>$route</span>, <span>$pos</span> + 1<span> ); </span><span>46</span><span>if</span> (! <span>isset</span> ( <span>$basePath</span> )) <span>//</span><span> first segment</span><span>47</span><span> { </span><span>48</span><span>$basePath</span> = <span>$owner</span>-><span>getControllerPath (); </span><span>49</span><span>$controllerID</span> = ''<span>; </span><span>50</span> } <span>else</span><span> { </span><span>51</span><span>$controllerID</span> .= '/'<span>; </span><span>52</span><span> } </span><span>53</span><span>$className</span> = <span>ucfirst</span> ( <span>$id</span> ) . 'Controller'<span>; </span><span>54</span><span>$classFile</span> = <span>$basePath</span> . DIRECTORY_SEPARATOR . <span>$className</span> . '.php'<span>; </span><span>55</span><span>56</span><span>if</span> (<span>is_file</span> ( <span>$classFile</span><span> )) { </span><span>57</span><span>if</span> (! <span>class_exists</span> ( <span>$className</span>, <span>false</span><span> )) </span><span>58</span><span>require</span> (<span>$classFile</span><span>); </span><span>59</span><span>if</span> (<span>class_exists</span> ( <span>$className</span>, <span>false</span> ) && <span>is_subclass_of</span> ( <span>$className</span>, 'CController'<span> )) { </span><span>60</span><span>$id</span> [0] = <span>strtolower</span> ( <span>$id</span> [0<span>] ); </span><span>61</span><span>return</span><span>array</span><span> ( </span><span>62</span><span>new</span><span>$className</span> ( <span>$controllerID</span> . <span>$id</span>, <span>$owner</span> === <span>$this</span> ? <span>null</span> : <span>$owner</span> ), <span>63</span><span>$this</span>->parseActionParams ( <span>$route</span><span> ) </span><span>64</span><span> ); </span><span>65</span><span> } </span><span>66</span><span>return</span><span>null</span><span>; </span><span>67</span><span> } </span><span>68</span><span>$controllerID</span> .= <span>$id</span><span>; </span><span>69</span><span>$basePath</span> .= DIRECTORY_SEPARATOR . <span>$id</span><span>; </span><span>70</span><span> } </span><span>71</span><span> } </span><span>72</span><span>protected</span><span>function</span> parseActionParams(<span>$pathInfo</span><span>) { </span><span>73</span><span>if</span> ((<span>$pos</span> = <span>strpos</span> ( <span>$pathInfo</span>, '/' )) !== <span>false</span><span>) { </span><span>74</span><span>$manager</span> = <span>$this</span>->getUrlManager ();<span>//</span><span>再次获取urlManager,在上面第一次调用中已经导入。</span><span>75</span><span>$manager</span>->parsePathInfo ( ( <span>string</span> ) <span>substr</span> ( <span>$pathInfo</span>, <span>$pos</span> + 1<span> ) ); </span><span>76</span><span>$actionID</span> = <span>substr</span> ( <span>$pathInfo</span>, 0, <span>$pos</span><span> ); </span><span>77</span><span>return</span><span>$manager</span>->caseSensitive ? <span>$actionID</span> : <span>strtolower</span> ( <span>$actionID</span><span> ); </span><span>78</span> } <span>else</span><span>79</span><span>return</span><span>$pathInfo</span><span>; </span><span>80</span><span> } </span><span>81</span><span>public</span><span>function</span><span> getControllerPath() { </span><span>82</span><span>if</span> (<span>$this</span>->_controllerPath !== <span>null</span><span>) </span><span>83</span><span>return</span><span>$this</span>-><span>_controllerPath; </span><span>84</span><span>else</span><span>85</span><span>return</span><span>$this</span>->_controllerPath = <span>$this</span>->getBasePath () . DIRECTORY_SEPARATOR . 'controllers'<span>; </span><span>86</span><span> } </span><span>87</span><span>//</span><span>两个钩子,子类去实现</span><span>88</span><span>public</span><span>function</span> beforeControllerAction(<span>$controller</span>, <span>$action</span><span>) { </span><span>89</span><span>return</span><span>true</span><span>; </span><span>90</span><span> } </span><span>91</span><span>public</span><span>function</span> afterControllerAction(<span>$controller</span>, <span>$action</span><span>) { </span><span>92</span><span> } </span><span>93</span><span>protected</span><span>function</span><span> init() { </span><span>94</span> parent::<span>init (); </span><span>95</span><span> } </span><span>96</span> }

$ca = $this->createController ($route)); createController의 기능은 $route에서 컨트롤러와 액션을 분리하여 컨트롤러 인스턴스를 생성하는 것입니다.

마지막으로 컨트롤러 인스턴스와 actionid가 반환됩니다.

그런 다음 CWebApplication의 runController($route),$controller->init();로 돌아가 컨트롤러가 초기화될 때 이를 실행합니다. 예를 들면 다음과 같습니다.

<span> 1</span><span>class</span> VideoController <span>extends</span><span> CController { </span><span> 2</span><span>public</span><span>function</span><span> init() { </span><span> 3</span><span>$this</span>->db = Yii::app ()-><span>db; </span><span> 4</span><span> } </span><span> 5</span><span>public</span><span>function</span><span> actionBroadcast() { </span><span> 6</span><span>$b</span> = <span>$this</span>->db->query ( "", <span>array</span> (1<span> ) ); </span><span> 7</span><span>$this</span>->render ( "u_broadcast", <span>array</span><span> ( </span><span> 8</span> 'b' => <span>$b</span> [0<span>] ; </span><span> 9</span><span> ) ); </span><span>10</span><span> } </span><span>11</span> }    

이런 방식으로 $this->db를 사용하여 VideoController에서 db 구성요소를 호출할 수 있습니다.

$controller->run ($actionID);Ccontroller로 전송합니다.

<span> 1</span> <?<span>php </span><span> 2</span><span>class</span><span> CController { </span><span> 3</span><span>protected</span><span>$db</span><span>; </span><span> 4</span><span>public</span><span>$defaultAction</span> = 'index'<span>; </span><span> 5</span><span>private</span><span>$_id</span><span>; </span><span> 6</span><span>private</span><span>$_action</span><span>; </span><span> 7</span><span>public</span><span>function</span> __construct(<span>$id</span>, <span>$module</span> = <span>null</span><span>) { </span><span> 8</span><span>$this</span>->_id = <span>$id</span><span>; </span><span> 9</span><span> } </span><span>10</span><span>public</span><span>function</span><span> init() { </span><span>11</span><span> } </span><span>12</span><span>//</span><span>过滤方法,子类重写</span><span>13</span><span>public</span><span>function</span><span> filters() { </span><span>14</span><span>return</span><span>array</span><span> (); </span><span>15</span><span> } </span><span>16</span><span>public</span><span>function</span> run(<span>$actionID</span><span>) { </span><span>17</span><span>//</span><span>创建action实例</span><span>18</span><span>if</span> ((<span>$action</span> = <span>$this</span>->createAction ( <span>$actionID</span> )) !== <span>null</span><span>) { </span><span>19</span><span>$parent</span> = Yii::<span>app (); </span><span>20</span><span>if</span> (<span>$parent</span>->beforeControllerAction ( <span>$this</span>, <span>$action</span><span> )) { </span><span>21</span><span>$this</span>->runActionWithFilters ( <span>$action</span>, <span>$this</span>-><span>filters () ); </span><span>22</span><span>$parent</span>->afterControllerAction ( <span>$this</span>, <span>$action</span><span> ); </span><span>23</span><span> } </span><span>24</span><span> } </span><span>25</span><span> } </span><span>26</span><span>public</span><span>function</span> refresh(<span>$terminate</span> = <span>true</span>, <span>$anchor</span> = ''<span>) { </span><span>27</span><span>$this</span>->redirect ( Yii::app ()->getRequest ()->getUrl () . <span>$anchor</span>, <span>$terminate</span><span> ); </span><span>28</span><span> } </span><span>29</span><span>public</span><span>function</span> redirect(<span>$url</span>, <span>$terminate</span> = <span>true</span>, <span>$statusCode</span> = 302<span>) { </span><span>30</span> Yii::app ()->getRequest ()->redirect ( <span>$url</span>, <span>$terminate</span>, <span>$statusCode</span><span> ); </span><span>31</span><span> } </span><span>32</span><span>//</span><span>如果controller里面有filter</span><span>33</span><span>public</span><span>function</span> runActionWithFilters(<span>$action</span>, <span>$filters</span><span>) { </span><span>34</span><span>if</span> (<span>empty</span> ( <span>$filters</span><span> )) </span><span>35</span><span>$this</span>->runAction ( <span>$action</span><span> ); </span><span>36</span><span>else</span><span> { </span><span>37</span><span>$priorAction</span> = <span>$this</span>-><span>_action; </span><span>38</span><span>$this</span>->_action = <span>$action</span><span>; </span><span>39</span> CFilterChain::create ( <span>$this</span>, <span>$action</span>, <span>$filters</span> )-><span>run (); </span><span>40</span><span>$this</span>->_action = <span>$priorAction</span><span>; </span><span>41</span><span> } </span><span>42</span><span> } </span><span>43</span><span>public</span><span>function</span> runAction(<span>$action</span><span>) { </span><span>44</span><span>$priorAction</span> = <span>$this</span>-><span>_action; </span><span>45</span><span>$this</span>->_action = <span>$action</span><span>; </span><span>46</span><span>if</span> (<span>$this</span>->beforeAction ( <span>$action</span><span> )) { </span><span>47</span><span>if</span> (<span>$action</span>->runWithParams ( <span>$this</span>->getActionParams () ) === <span>false</span><span>) </span><span>48</span><span>$this</span>->invalidActionParams ( <span>$action</span><span> ); </span><span>49</span><span>else</span><span>50</span><span>$this</span>->afterAction ( <span>$action</span><span> ); </span><span>51</span><span> } </span><span>52</span><span>$this</span>->_action = <span>$priorAction</span><span>; </span><span>53</span><span> } </span><span>54</span><span>//</span><span>渲染视图</span><span>55</span><span>public</span><span>function</span> render(<span>$view</span>, <span>$data</span> = <span>array</span><span>()) { </span><span>56</span><span>if</span> (<span>isset</span> ( <span>$data</span><span> )) </span><span>57</span><span>extract</span> ( <span>$data</span><span> ); </span><span>58</span><span>include</span> VIEWS_DIR . "/" . <span>$this</span>->_id . "/" . <span>$view</span> . ".php"<span>; </span><span>59</span><span> } </span><span>60</span><span>public</span><span>function</span> renderFile(<span>$file</span>, <span>$data</span> = <span>array</span><span>()) { </span><span>61</span><span>if</span> (<span>isset</span> ( <span>$data</span><span> )) </span><span>62</span><span>extract</span> ( <span>$data</span><span> ); </span><span>63</span><span>include</span> VIEWS_DIR . "/" . <span>$file</span><span>; </span><span>64</span><span> } </span><span>65</span><span>//</span><span>跳转到另一个controller/action,不过浏览器的地址没有变</span><span>66</span><span>public</span><span>function</span> forward(<span>$route</span><span>) { </span><span>67</span><span>if</span> (<span>strpos</span> ( <span>$route</span>, '/' ) === <span>false</span><span>) </span><span>68</span><span>$this</span>->run ( <span>$route</span><span> ); </span><span>69</span><span>else</span><span> { </span><span>70</span><span>//</span><span>不在同一个controller里面,重新创建</span><span>71</span> Yii::app ()->runController ( <span>$route</span><span> ); </span><span>72</span><span> } </span><span>73</span><span> } </span><span>74</span><span>public</span><span>function</span><span> getActionParams() { </span><span>75</span><span>return</span><span>$_GET</span><span>; </span><span>76</span><span> } </span><span>77</span><span>public</span><span>function</span> createAction(<span>$actionID</span><span>) { </span><span>78</span><span>if</span> (<span>$actionID</span> === ''<span>) </span><span>79</span><span>$actionID</span> = <span>$this</span>-><span>defaultAction; </span><span>80</span><span>if</span> (<span>method_exists</span> ( <span>$this</span>, 'action' . <span>$actionID</span> ) && <span>strcasecmp</span> ( <span>$actionID</span>, 's'<span> )) </span><span>81</span><span>return</span><span>new</span> CInlineAction ( <span>$this</span>, <span>$actionID</span><span> ); </span><span>82</span><span> } </span><span>83</span><span>public</span><span>function</span><span> getAction() { </span><span>84</span><span>return</span><span>$this</span>-><span>_action; </span><span>85</span><span> } </span><span>86</span><span>public</span><span>function</span> setAction(<span>$value</span><span>) { </span><span>87</span><span>$this</span>->_action = <span>$value</span><span>; </span><span>88</span><span> } </span><span>89</span><span>public</span><span>function</span><span> getId() { </span><span>90</span><span>return</span><span>$this</span>-><span>_id; </span><span>91</span><span> } </span><span>92</span><span>//</span><span>两个钩子</span><span>93</span><span>protected</span><span>function</span> beforeAction(<span>$action</span><span>) { </span><span>94</span><span>return</span><span>true</span><span>; </span><span>95</span><span> } </span><span>96</span><span>protected</span><span>function</span> afterAction(<span>$action</span><span>) { </span><span>97</span><span> } </span><span>98</span> }

$this->createAction( $actionID ); 액션 인스턴스를 생성합니다.

그런 다음 runActionWithFilters($action, $filters); filter()가 없으면 직접 runAction($action)을 실행합니다.

$action->runWithParams ( $this->getActionParams () ).$action은 CInlineAction 인스턴스입니다.

<span> 1</span> <?<span>php </span><span> 2</span><span>class</span> CInlineAction <span>extends</span><span> CAction </span><span> 3</span><span>{ </span><span> 4</span><span>//</span><span>执行该动作</span><span> 5</span><span>public</span><span>function</span><span> run() </span><span> 6</span><span> { </span><span> 7</span><span>$method</span>='action'.<span>$this</span>-><span>getId(); </span><span> 8</span><span>$this</span>->getController()-><span>$method</span><span>(); </span><span> 9</span><span> } </span><span>10</span><span>//</span><span>执行带提供的请求的参数的动作</span><span>11</span><span>public</span><span>function</span> runWithParams(<span>$params</span><span>) </span><span>12</span><span> { </span><span>13</span><span>$methodName</span>='action'.<span>$this</span>->getId();<span>//</span><span>拼接action方法</span><span>14</span><span>$controller</span>=<span>$this</span>-><span>getController(); </span><span>15</span><span>$method</span>=<span>new</span> ReflectionMethod(<span>$controller</span>, <span>$methodName</span>);<span>//</span><span>反射</span><span>16</span><span>if</span>(<span>$method</span>->getNumberOfParameters()>0)<span>//</span><span>方法参数个数>0</span><span>17</span><span>return</span><span>$this</span>->runWithParamsInternal(<span>$controller</span>, <span>$method</span>, <span>$params</span><span>); </span><span>18</span><span>else</span><span>19</span><span>return</span><span>$controller</span>-><span>$methodName</span><span>(); </span><span>20</span><span> } </span><span>21</span> }

C액션

<span> 1</span> <?<span>php </span><span> 2</span><span>abstract</span><span>class</span> CAction <span>extends</span><span> CComponent </span><span> 3</span><span>{ </span><span> 4</span><span>private</span><span>$_id</span><span>; </span><span> 5</span><span>private</span><span>$_controller</span><span>; </span><span> 6</span><span>public</span><span>function</span> __construct(<span>$controller</span>,<span>$id</span><span>) </span><span> 7</span><span> { </span><span> 8</span><span>$this</span>->_controller=<span>$controller</span><span>; </span><span> 9</span><span>$this</span>->_id=<span>$id</span><span>; </span><span>10</span><span> } </span><span>11</span><span>public</span><span>function</span><span> getController() </span><span>12</span><span> { </span><span>13</span><span>return</span><span>$this</span>-><span>_controller; </span><span>14</span><span> } </span><span>15</span><span>public</span><span>function</span><span> getId() </span><span>16</span><span> { </span><span>17</span><span>return</span><span>$this</span>-><span>_id; </span><span>18</span><span> } </span><span>19</span><span>//</span><span>运行带有请求参数的对象。 这个方法通过CController::runAction()内部调用</span><span>20</span><span>public</span><span>function</span> runWithParams(<span>$params</span><span>) </span><span>21</span><span> { </span><span>22</span><span>$method</span>=<span>new</span> ReflectionMethod(<span>$this</span>, 'run'<span>); </span><span>23</span><span>if</span>(<span>$method</span>->getNumberOfParameters()>0<span>) </span><span>24</span><span>return</span><span>$this</span>->runWithParamsInternal(<span>$this</span>, <span>$method</span>, <span>$params</span><span>); </span><span>25</span><span>else</span><span>26</span><span>return</span><span>$this</span>-><span>run(); </span><span>27</span><span> } </span><span>28</span><span>//</span><span>执行一个带有命名参数的对象的方法</span><span>29</span><span>protected</span><span>function</span> runWithParamsInternal(<span>$object</span>, <span>$method</span>, <span>$params</span><span>) </span><span>30</span><span> { </span><span>31</span><span>$ps</span>=<span>array</span><span>(); </span><span>32</span><span>foreach</span>(<span>$method</span>->getParameters() <span>as</span><span>$i</span>=><span>$param</span><span>) </span><span>33</span><span> { </span><span>34</span><span>$name</span>=<span>$param</span>-><span>getName(); </span><span>35</span><span>if</span>(<span>isset</span>(<span>$params</span>[<span>$name</span><span>])) </span><span>36</span><span> { </span><span>37</span><span>if</span>(<span>$param</span>-><span>isArray()) </span><span>38</span><span>$ps</span>[]=<span>is_array</span>(<span>$params</span>[<span>$name</span>]) ? <span>$params</span>[<span>$name</span>] : <span>array</span>(<span>$params</span>[<span>$name</span><span>]); </span><span>39</span><span>elseif</span>(!<span>is_array</span>(<span>$params</span>[<span>$name</span><span>])) </span><span>40</span><span>$ps</span>[]=<span>$params</span>[<span>$name</span><span>]; </span><span>41</span><span>else</span><span>42</span><span>return</span><span>false</span><span>; </span><span>43</span><span> } </span><span>44</span><span>elseif</span>(<span>$param</span>-><span>isDefaultValueAvailable()) </span><span>45</span><span>$ps</span>[]=<span>$param</span>-><span>getDefaultValue(); </span><span>46</span><span>else</span><span>47</span><span>return</span><span>false</span><span>; </span><span>48</span><span> } </span><span>49</span><span>$method</span>->invokeArgs(<span>$object</span>,<span>$ps</span>);<span>//</span><span>反射,执行</span><span>50</span><span>return</span><span>true</span><span>; </span><span>51</span><span> } </span><span>52</span> }

두 클래스 모두 매우 간단합니다. 컨트롤러 클래스에서 작업 메서드를 실행하기만 하면 됩니다.

위의 runActionWithFilters($action, $filters)로 돌아가십시오. filter()가 있으면 CFilterChain::create ( $this, $action, $filters )->run ();

물론, 필터가 있는 경우 액션 메소드를 실행하기 전에 필터 목록을 설정해야 합니다.

CFilterChain은 'application.filters.LoginFilter+upload_video'와 유사한 구성을 필터 체인으로 구문 분석합니다.

필터 체인의 각 항목은 CInlineFilter 또는 CFilter 인스턴스입니다.

<span> 1</span> <?<span>php </span><span> 2</span><span>//</span><span>过滤器列表</span><span> 3</span><span>class</span> CFilterChain <span>extends</span><span> CList { </span><span> 4</span><span>public</span><span>$controller</span><span>; </span><span> 5</span><span>public</span><span>$action</span><span>; </span><span> 6</span><span>public</span><span>$filterIndex</span> = 0<span>; </span><span> 7</span><span>public</span><span>function</span> __construct(<span>$controller</span>, <span>$action</span><span>) { </span><span> 8</span><span>$this</span>->controller = <span>$controller</span><span>; </span><span> 9</span><span>$this</span>->action = <span>$action</span><span>; </span><span>10</span><span> } </span><span>11</span><span>//</span><span>创建过滤器列表</span><span>12</span><span>public</span><span>static</span><span>function</span> create(<span>$controller</span>, <span>$action</span>, <span>$filters</span><span>) { </span><span>13</span><span>$chain</span> = <span>new</span> CFilterChain ( <span>$controller</span>, <span>$action</span><span> ); </span><span>14</span><span>$actionID</span> = <span>$action</span>-><span>getId (); </span><span>15</span><span>foreach</span> ( <span>$filters</span><span>as</span><span>$filter</span><span> ) { </span><span>16</span><span>if</span> (<span>is_string</span> ( <span>$filter</span> )) <span>//</span><span> filterName [+|- action1 action2]</span><span>17</span><span> { </span><span>18</span><span>if</span> ((<span>$pos</span> = <span>strpos</span> ( <span>$filter</span>, '+' )) !== <span>false</span> || (<span>$pos</span> = <span>strpos</span> ( <span>$filter</span>, '-' )) !== <span>false</span><span>) { </span><span>19</span><span>$matched</span> = <span>preg_match</span> ( "/\b{<span>$actionID</span>}\b/i", <span>substr</span> ( <span>$filter</span>, <span>$pos</span> + 1 ) ) > 0<span>; </span><span>20</span><span>if</span> ((<span>$filter</span> [<span>$pos</span>] === '+') === <span>$matched</span><span>) </span><span>21</span><span>$filter</span> = CInlineFilter::create ( <span>$controller</span>, <span>trim</span> ( <span>substr</span> ( <span>$filter</span>, 0, <span>$pos</span><span> ) ) ); </span><span>22</span> } <span>else</span><span>23</span><span>$filter</span> = CInlineFilter::create ( <span>$controller</span>, <span>$filter</span><span> ); </span><span>24</span> } <span>elseif</span> (<span>is_array</span> ( <span>$filter</span> )) <span>//</span><span> array('path.to.class [+|- action1, action2]','param1'=>'value1',...)</span><span>25</span><span> { </span><span>26</span><span>$filterClass</span> = <span>$filter</span> [0<span>]; </span><span>27</span><span>unset</span> ( <span>$filter</span> [0<span>] ); </span><span>28</span><span>//</span><span>开始解析过滤器配置</span><span>29</span><span>if</span> ((<span>$pos</span> = <span>strpos</span> ( <span>$filterClass</span>, '+' )) !== <span>false</span> || (<span>$pos</span> = <span>strpos</span> ( <span>$filterClass</span>, '-' )) !== <span>false</span><span>) { </span><span>30</span><span>preg_match</span> ( "/\b{<span>$actionID</span>}\b/i", <span>substr</span> ( <span>$filterClass</span>, <span>$pos</span> + 1 ), <span>$a</span><span> ); </span><span>31</span><span>$matched</span> = <span>preg_match</span> ( "/\b{<span>$actionID</span>}\b/i", <span>substr</span> ( <span>$filterClass</span>, <span>$pos</span> + 1 ) ) > 0<span>; </span><span>32</span><span>//</span><span>如果是filterName+action,创建一个过滤器,否则忽略</span><span>33</span><span>if</span> ((<span>$filterClass</span> [<span>$pos</span>] === '+') === <span>$matched</span><span>) { </span><span>34</span><span>//</span><span>解析出过滤器的类名</span><span>35</span><span>$filterClass</span> = <span>trim</span> ( <span>substr</span> ( <span>$filterClass</span>, 0, <span>$pos</span><span> ) ); </span><span>36</span> } <span>else</span><span>37</span><span>continue</span><span>; </span><span>38</span><span> } </span><span>39</span><span>$filter</span> ['class'] = <span>$filterClass</span><span>; </span><span>40</span><span>$filter</span> = Yii::createComponent ( <span>$filter</span><span> ); </span><span>41</span><span> } </span><span>42</span><span>43</span><span>if</span> (<span>is_object</span> ( <span>$filter</span><span> )) { </span><span>44</span><span>$filter</span>-><span>init (); </span><span>45</span><span>$chain</span>->add ( <span>$filter</span> );<span>//</span><span>list添加过滤器</span><span>46</span><span> } </span><span>47</span><span> } </span><span>48</span><span>return</span><span>$chain</span><span>; </span><span>49</span><span> } </span><span>50</span><span>public</span><span>function</span><span> run() { </span><span>51</span><span>if</span> (<span>$this</span>->offsetExists ( <span>$this</span>->filterIndex )) {<span>//</span><span>过滤器列表个数不为0 </span><span>52</span><span> //取出过滤器实例</span><span>53</span><span>$filter</span> = <span>$this</span>->itemAt ( <span>$this</span>->filterIndex ++<span> ); </span><span>54</span><span>$filter</span>->filter ( <span>$this</span><span> ); </span><span>55</span> } <span>else</span><span>56</span><span>$this</span>->controller->runAction ( <span>$this</span>-><span>action ); </span><span>57</span><span> } </span><span>58</span> }

'application.filters.LoginFilter+upload_video' 이 구성은 CFilter 인스턴스를 생성합니다.

<span> 1</span> <?<span>php </span><span> 2</span><span>class</span> CFilter <span>extends</span><span> CComponent { </span><span> 3</span><span>public</span><span>function</span> filter(<span>$filterChain</span><span>) { </span><span> 4</span><span>//</span><span>前置,后置方法</span><span> 5</span><span>if</span> (<span>$this</span>->preFilter ( <span>$filterChain</span><span> )) { </span><span> 6</span><span>$filterChain</span>-><span>run (); </span><span> 7</span><span>$this</span>->postFilter ( <span>$filterChain</span><span> ); </span><span> 8</span><span> } </span><span> 9</span><span> } </span><span>10</span><span>//</span><span>钩子</span><span>11</span><span>public</span><span>function</span><span> init() { </span><span>12</span><span> } </span><span>13</span><span>protected</span><span>function</span> preFilter(<span>$filterChain</span><span>) { </span><span>14</span><span>return</span><span>true</span><span>; </span><span>15</span><span> } </span><span>16</span><span>protected</span><span>function</span> postFilter(<span>$filterChain</span><span>) { </span><span>17</span><span> } </span><span>18</span> }

그런 다음 위에 있는 CFilterChain::create ($this, $action, $filters)->run(); 요청에 의해 구문 분석된 작업이 upload_video인 경우 Yii는 LoginFilter 인스턴스를 제거합니다.

예를 들어 내 LoginFilter

<span> 1</span> <?<span>php </span><span> 2</span><span>class</span> LoginFilter <span>extends</span><span> CFilter { </span><span> 3</span><span>protected</span><span>function</span> preFilter(<span>$filterChain</span><span>) { </span><span> 4</span><span>if</span> (! <span>isset</span> ( <span>$_SESSION</span><span> )) { </span><span> 5</span><span>session_start</span><span> (); </span><span> 6</span><span> } </span><span> 7</span><span>if</span> (<span>isset</span> ( <span>$_SESSION</span> ['user'<span>] )) </span><span> 8</span><span>return</span><span>true</span><span>; </span><span> 9</span><span>else</span><span> { </span><span>10</span><span>setcookie</span> ( "return", Yii::app ()->getRequest ()->getUrl (), <span>time</span> () + 360, '/'<span> ); </span><span>11</span> Yii::app ()->getRequest ()->redirect ( 'http://localhost/youtube/login', <span>true</span>, 302<span> ); </span><span>12</span><span>return</span><span>false</span><span>; </span><span>13</span><span> } </span><span>14</span><span> } </span><span>15</span><span>protected</span><span>function</span> postFilter(<span>$filterChain</span><span>) { </span><span>16</span><span> } </span><span>17</span><span>} </span><span>18</span> ?>

내부에 prefix와 postfix가 있는데, 이는 필터를 활성화해야 하는 액션 메서드에 대해 자체 정의된 preFilter 및 postFilter 메서드가 액션 메서드 실행 전과 후에 각각 실행된다는 의미입니다.

그리고 $filterChain->run()이 있습니다. 여기서는 실수하기 쉽습니다.

사실, CFilterChain에서 run()을 다시 사용하고 내부에서 $this->filterIndex++를 발견했는데, 이는 약간 재귀와 비슷합니다.

필터가 작업을 필터링하는 경우 이와 같이 CFilter로 이동한 다음 $filterChain->run();을 실행하고 $this->filterIndex++를 반환하고 $filterChain->run()을 계속합니다. . . . . . .

내 'application.filters.LoginFilter+upload_video'의 경우 upload_video 액션만 필터링되므로 CFilterChain이 반환되면 $this->filterIndex가 1이 되고 필터 목록에는 필터 인스턴스가 하나만 있으므로 이번에는 $this->controller->runAction( $this->action );으로 이동하며 이는 필터가 설정되지 않은 경우 $this->runAction( $action )과 동일합니다.

필터가 분석된 후에는 몇 가지 데이터 작업 등이 있고 마지막으로 렌더링 뷰 render()가 있습니다. 이는 너무 간단합니다. 추출($data)한 다음 뷰 파일을 포함합니다.

다른 컨트롤러/액션으로 점프하는 전달() 메소드도 있습니다. 핵심은 CWebApplication의 runController로 돌아가서 위의 분석 프로세스를 반복하는 것입니다.

마지막으로 잘린 yii http://files.cnblogs.com/TheViper/framework.zip이 첨부되어 있습니다.

이상으로 yii 프레임워크 소스코드 내용을 포함하여 yii 프레임워크 소스코드 분석(3)을 소개하였습니다. PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되었으면 좋겠습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.