yii2源码学习笔记(八),yii2源码学习笔记
Action是所有控制器的基类,接下来了解一下它的源码。yii2\base\Action.php
<span> 1</span> <?<span>php </span><span> 2</span> <span>/*</span><span>* </span><span> 3</span> <span> * @link </span><span>http://www.yiiframework.com/</span> <span> 4</span> <span> * @copyright Copyright (c) 2008 Yii Software LLC </span><span> 5</span> <span> * @license </span><span>http://www.yiiframework.com/license/</span> <span> 6</span> <span>*/</span> <span> 7</span> <span> 8</span> <span>namespace</span> yii\<span>base</span><span>; </span><span> 9</span> <span> 10</span> <span>use Yii; </span><span> 11</span> <span> 12</span> <span>/*</span><span>* </span><span> 13</span> <span> * Action is the base class for all controller action classes. </span><span> 14</span> <span> * 是所有控制器的基类 </span><span> 15</span> <span> * Action provides a way to divide a complex controller into </span><span> 16</span> <span> * smaller actions in separate class files. </span><span> 17</span> <span> * 控制器提供了一种重复使用操作方法的代码,在多个控制器或不同的项目中使用 </span><span> 18</span> <span> * Derived classes must implement a method named `run()`. This method </span><span> 19</span> <span> * will be invoked by the controller when the action is requested. </span><span> 20</span> <span> * The `run()` method can have parameters which will be filled up </span><span> 21</span> <span> * with user input values automatically according to their names. </span><span> 22</span> <span> * 派生类必须实现一个名为run()的方法,这个方法会在控制器被请求时调用。 </span><span> 23</span> <span> * 它可以有参数,将用户输入值的根据他们的名字自动填补。 </span><span> 24</span> <span> * For example, if the `run()` method is declared as follows: </span><span> 25</span> <span> * 例:run()方法调用声明如下: </span><span> 26</span> <span> * ~~~ </span><span> 27</span> <span> * public function run($id, $type = 'book') { ... } </span><span> 28</span> <span> * ~~~ </span><span> 29</span> <span> * </span><span> 30</span> <span> * And the parameters provided for the action are: `['id' => 1]`. </span><span> 31</span> <span> * Then the `run()` method will be invoked as `run(1)` automatically. </span><span> 32</span> <span> * 并且提供了操作的参数 ['id'=>1]; </span><span> 33</span> <span> * 当run(1)时自动调用run(); </span><span> 34</span> <span> * @property string $uniqueId The unique ID of this action among the whole application. This property is </span><span> 35</span> <span> * read-only. </span><span> 36</span> <span> * 整个应用程序中,这一行动的唯一标识。此属性是只读 </span><span> 37</span> <span> * @author Qiang Xue <qiang.xue@gmail.com> </span><span> 38</span> <span> * @since 2.0 </span><span> 39</span> <span>*/</span> <span> 40</span> <span>class</span><span> Action extends Component </span><span> 41</span> <span>{ </span><span> 42</span> <span>/*</span><span>* </span><span> 43</span> <span> * @var string ID of the action ID的动作 </span><span> 44</span> <span>*/</span> <span> 45</span> <span>public</span><span> $id; </span><span> 46</span> <span>/*</span><span>* </span><span> 47</span> <span> * @var Controller|\yii\web\Controller the controller that owns this action </span><span> 48</span> <span> * 拥有这一行动的控制器 </span><span> 49</span> <span>*/</span> <span> 50</span> <span>public</span><span> $controller; </span><span> 51</span> <span> 52</span> <span> 53</span> <span>/*</span><span>* </span><span> 54</span> <span> * Constructor. </span><span> 55</span> <span> * 构造函数 </span><span> 56</span> <span> * @param string $id the ID of this action 这一行动的ID </span><span> 57</span> <span> * @param Controller $controller the controller that owns this action 拥有这一行动的控制器 </span><span> 58</span> <span> * @param array $config name-value pairs that will be used to initialize the object properties </span><span> 59</span> <span> * 用来初始化对象属性的 name-value </span><span> 60</span> <span>*/</span> <span> 61</span> <span>public</span> function __construct($id, $controller, $config =<span> []) </span><span> 62</span> <span> { </span><span> 63</span> $<span>this</span>->id =<span> $id; </span><span> 64</span> $<span>this</span>->controller =<span> $controller; </span><span> 65</span> <span>//</span><span>调用父类的__construct()方法</span> <span> 66</span> <span> parent::__construct($config); </span><span> 67</span> <span> } </span><span> 68</span> <span> 69</span> <span>/*</span><span>* </span><span> 70</span> <span> * Returns the unique ID of this action among the whole application. </span><span> 71</span> <span> * 返回整个应用程序中的唯一ID。 </span><span> 72</span> <span> * @return string the unique ID of this action among the whole application. </span><span> 73</span> <span> * 在整个应用程序中,这一行动的唯一ID。 </span><span> 74</span> <span>*/</span> <span> 75</span> <span>public</span><span> function getUniqueId() </span><span> 76</span> <span> { </span><span> 77</span> <span>return</span> $<span>this</span>->controller->getUniqueId() . <span>'</span><span>/</span><span>'</span> . $<span>this</span>-><span>id; </span><span> 78</span> <span> } </span><span> 79</span> <span> 80</span> <span>/*</span><span>* </span><span> 81</span> <span> * Runs this action with the specified parameters. 用指定的参数运行此操作。 </span><span> 82</span> <span> * This method is mainly invoked by the controller. 该方法主要由控制器调用。 </span><span> 83</span> <span> * </span><span> 84</span> <span> * @param array $params the parameters to be bound to the action's run() method.绑定到行动的run()方法的参数。 </span><span> 85</span> <span> * @return mixed the result of the action 行动的结果 命名参数是否有效的 </span><span> 86</span> <span> * @throws InvalidConfigException if the action class does not have a run() method </span><span> 87</span> <span> * 如果动作类没有run()方法 扔出异常 </span><span> 88</span> <span>*/</span> <span> 89</span> <span>public</span> function runWithParams($<span>params</span><span>) </span><span> 90</span> <span> { </span><span> 91</span> <span>if</span> (!method_exists($<span>this</span>, <span>'</span><span>run</span><span>'</span>)) {<span>//</span><span>如果动作类没有run()方法 抛出异常</span> <span> 92</span> <span>throw</span> <span>new</span> InvalidConfigException(get_class($<span>this</span>) . <span>'</span><span> must define a "run()" method.</span><span>'</span><span>); </span><span> 93</span> <span> } </span><span> 94</span> <span>//</span><span>调用bindActionParams()方法将参数绑定到动作。</span> <span> 95</span> $args = $<span>this</span>->controller->bindActionParams($<span>this</span>, $<span>params</span><span>); </span><span> 96</span> <span>//</span><span>记录跟踪消息</span> <span> 97</span> Yii::trace(<span>'</span><span>Running action: </span><span>'</span> . get_class($<span>this</span>) . <span>'</span><span>::run()</span><span>'</span><span>, __METHOD__); </span><span> 98</span> <span>if</span> (Yii::$app->requestedParams === <span>null</span><span>) { </span><span> 99</span> <span>//</span><span>请求的动作提供的参数</span> <span>100</span> Yii::$app->requestedParams =<span> $args; </span><span>101</span> <span> } </span><span>102</span> <span>if</span> ($<span>this</span>-><span>beforeRun()) { </span><span>103</span> <span>//</span><span>执行run()方法</span> <span>104</span> $result = call_user_func_array([$<span>this</span>, <span>'</span><span>run</span><span>'</span><span>], $args); </span><span>105</span> $<span>this</span>-><span>afterRun(); </span><span>106</span> <span>107</span> <span>return</span><span> $result; </span><span>108</span> } <span>else</span><span> { </span><span>109</span> <span>return</span> <span>null</span><span>; </span><span>110</span> <span> } </span><span>111</span> <span> } </span><span>112</span> <span>113</span> <span>/*</span><span>* </span><span>114</span> <span> * This method is called right before `run()` is executed. </span><span>115</span> <span> * ` run() `执行前方法被调用。 </span><span>116</span> <span> * You may override this method to do preparation work for the action run. </span><span>117</span> <span> * 可以重写此方法,为该操作运行的准备工作。 </span><span>118</span> <span> * If the method returns false, it will cancel the action. </span><span>119</span> <span> * 如果该方法返回false,取消该操作。 </span><span>120</span> <span> * @return boolean whether to run the action. </span><span>121</span> <span>*/</span> <span>122</span> <span>protected</span><span> function beforeRun() </span><span>123</span> <span> { </span><span>124</span> <span>return</span> <span>true</span><span>; </span><span>125</span> <span> } </span><span>126</span> <span>127</span> <span>/*</span><span>* </span><span>128</span> <span> * This method is called right after `run()` is executed. ` run() `执行后 方法被调用。 </span><span>129</span> <span> * You may override this method to do post-processing work for the action run. </span><span>130</span> <span> * 可以重写此方法来处理该动作的后续处理工作。 </span><span>131</span> <span>*/</span> <span>132</span> <span>protected</span><span> function afterRun() </span><span>133</span> <span> { </span><span>134</span> <span> } </span><span>135</span> }
接下来我们看一下事件参数相关重要的一个类ActionEvent。yii2\base\ActionEvent.php
<span> 1</span> <?<span>php </span><span> 2</span> <span>/*</span><span>* </span><span> 3</span> <span> * @link </span><span>http://www.yiiframework.com/</span> <span> 4</span> <span> * @copyright Copyright (c) 2008 Yii Software LLC </span><span> 5</span> <span> * @license </span><span>http://www.yiiframework.com/license/</span> <span> 6</span> <span>*/</span> <span> 7</span> <span> 8</span> <span>namespace</span> yii\<span>base</span><span>; </span><span> 9</span> <span>10</span> <span>/*</span><span>* </span><span>11</span> <span> * ActionEvent represents the event parameter used for an action event. </span><span>12</span> <span> * 用于操作事件的事件参数 </span><span>13</span> <span> * By setting the [[isValid]] property, one may control whether to continue running the action. </span><span>14</span> <span> * 通过设置[[isValid]]属性,控制是否继续运行action。 </span><span>15</span> <span> * @author Qiang Xue <qiang.xue@gmail.com> </span><span>16</span> <span> * @since 2.0 </span><span>17</span> <span>*/</span> <span>18</span> <span>class</span><span> ActionEvent extends Event </span><span>19</span> <span>{ </span><span>20</span> <span>/*</span><span>* </span><span>21</span> <span> * @var Action the action currently being executed </span><span>22</span> <span> * 目前正在执行的行动 </span><span>23</span> <span>*/</span> <span>24</span> <span>public</span><span> $action; </span><span>25</span> <span>/*</span><span>* </span><span>26</span> <span> * @var mixed the action result. Event handlers may modify this property to change the action result. </span><span>27</span> <span> * 操作结果 事件处理程序可以修改此属性来更改操作结果。 </span><span>28</span> <span>*/</span> <span>29</span> <span>public</span><span> $result; </span><span>30</span> <span>/*</span><span>* </span><span>31</span> <span> * @var boolean whether to continue running the action. Event handlers of </span><span>32</span> <span> * [[Controller::EVENT_BEFORE_ACTION]] may set this property to decide whether </span><span>33</span> <span> * to continue running the current action. </span><span>34</span> <span> * 是否继续运行该动作。设置[[Controller::EVENT_BEFORE_ACTION]]属性决定是否执行当前的操作 </span><span>35</span> <span>*/</span> <span>36</span> <span>public</span> $isValid = <span>true</span><span>; </span><span>37</span> <span>38</span> <span>39</span> <span>/*</span><span>* </span><span>40</span> <span> * Constructor.构造函数。 </span><span>41</span> <span> * @param Action $action the action associated with this action event.与此事件相关联的动作。 </span><span>42</span> <span> * @param array $config name-value pairs that will be used to initialize the object properties </span><span>43</span> <span> * 用来初始化对象属性的 name-value </span><span>44</span> <span>*/</span> <span>45</span> <span>public</span> function __construct($action, $config =<span> []) </span><span>46</span> <span> { </span><span>47</span> $<span>this</span>->action =<span> $action; </span><span>48</span> <span> parent::__construct($config); </span><span>49</span> <span> } </span><span>50</span> }
今天最后看一下操作过滤器的基类吧ActionFilter。yii2\base\ActionFilter.php。
<span> 1</span> <?<span>php </span><span> 2</span> <span>/*</span><span>* </span><span> 3</span> <span> * @link </span><span>http://www.yiiframework.com/</span> <span> 4</span> <span> * @copyright Copyright (c) 2008 Yii Software LLC </span><span> 5</span> <span> * @license </span><span>http://www.yiiframework.com/license/</span> <span> 6</span> <span>*/</span> <span> 7</span> <span> 8</span> <span>namespace</span> yii\<span>base</span><span>; </span><span> 9</span> <span> 10</span> <span>/*</span><span>* </span><span> 11</span> <span> * ActionFilter is the base class for action filters. </span><span> 12</span> <span> * 是操作过滤器的基类。 </span><span> 13</span> <span> * An action filter will participate in the action execution workflow by responding to </span><span> 14</span> <span> * the `beforeAction` and `afterAction` events triggered by modules and controllers. </span><span> 15</span> <span> * 一个操作过滤器将参与行动的执行工作流程,通过触发模型和控制器的`beforeAction` 和`afterAction` 事件 </span><span> 16</span> <span> * Check implementation of [[\yii\filters\AccessControl]], [[\yii\filters\PageCache]] and [[\yii\filters\HttpCache]] as examples on how to use it. </span><span> 17</span> <span> * </span><span> 18</span> <span> * @author Qiang Xue <qiang.xue@gmail.com> </span><span> 19</span> <span> * @since 2.0 </span><span> 20</span> <span>*/</span> <span> 21</span> <span>class</span><span> ActionFilter extends Behavior </span><span> 22</span> <span>{ </span><span> 23</span> <span>/*</span><span>* </span><span> 24</span> <span> * @var array list of action IDs that this filter should apply to. If this property is not set, </span><span> 25</span> <span> * then the filter applies to all actions, unless they are listed in [[except]]. </span><span> 26</span> <span> * 操作标识列表。如果该属性未设置,过滤器适用于所有的行动,除非它们被列入[[except]]中。 </span><span> 27</span> <span> * If an action ID appears in both [[only]] and [[except]], this filter will NOT apply to it. </span><span> 28</span> <span> * 如果一个操作ID 出现在[[only]] 和[[except]]中,该筛选器将不适用它 </span><span> 29</span> <span> * Note that if the filter is attached to a module, the action IDs should also include child module IDs (if any) </span><span> 30</span> <span> * and controller IDs. </span><span> 31</span> <span> * 如果过滤器是链接到一个模块,操作检测还应包括子模块和控制器 </span><span> 32</span> <span> * </span><span> 33</span> <span> * @see except </span><span> 34</span> <span>*/</span> <span> 35</span> <span>public</span><span> $only; </span><span> 36</span> <span>/*</span><span>* </span><span> 37</span> <span> * @var array list of action IDs that this filter should not apply to. </span><span> 38</span> <span> * 此筛选器不应适用于操作ID。 </span><span> 39</span> <span> * @see only </span><span> 40</span> <span>*/</span> <span> 41</span> <span>public</span> $except =<span> []; </span><span> 42</span> <span> 43</span> <span> 44</span> <span>/*</span><span>* </span><span> 45</span> <span> * @inheritdoc </span><span> 46</span> <span> * 将行为对象附加到组件。 </span><span> 47</span> <span>*/</span> <span> 48</span> <span>public</span><span> function attach($owner) </span><span> 49</span> <span> { </span><span> 50</span> $<span>this</span>->owner =<span> $owner; </span><span> 51</span> $owner->on(Controller::EVENT_BEFORE_ACTION, [$<span>this</span>, <span>'</span><span>beforeFilter</span><span>'</span><span>]); </span><span> 52</span> <span> } </span><span> 53</span> <span> 54</span> <span>/*</span><span>* </span><span> 55</span> <span> * @inheritdoc </span><span> 56</span> <span> * 将行为对象和组件分离。 </span><span> 57</span> <span>*/</span> <span> 58</span> <span>public</span><span> function detach() </span><span> 59</span> <span> { </span><span> 60</span> <span>if</span> ($<span>this</span>-><span>owner) { </span><span> 61</span> $<span>this</span>->owner->off(Controller::EVENT_BEFORE_ACTION, [$<span>this</span>, <span>'</span><span>beforeFilter</span><span>'</span><span>]); </span><span> 62</span> $<span>this</span>->owner->off(Controller::EVENT_AFTER_ACTION, [$<span>this</span>, <span>'</span><span>afterFilter</span><span>'</span><span>]); </span><span> 63</span> $<span>this</span>->owner = <span>null</span><span>; </span><span> 64</span> <span> } </span><span> 65</span> <span> } </span><span> 66</span> <span> 67</span> <span>/*</span><span>* </span><span> 68</span> <span> * @param ActionEvent $event 在动作之前调用 </span><span> 69</span> <span>*/</span> <span> 70</span> <span>public</span> function beforeFilter($<span>event</span><span>) </span><span> 71</span> <span> { </span><span> 72</span> <span>if</span> (!$<span>this</span>->isActive($<span>event</span>-><span>action)) { </span><span> 73</span> <span>return</span><span>; </span><span> 74</span> <span> } </span><span> 75</span> <span> 76</span> $<span>event</span>->isValid = $<span>this</span>->beforeAction($<span>event</span>-><span>action); </span><span> 77</span> <span>if</span> ($<span>event</span>-><span>isValid) { </span><span> 78</span> <span>//</span><span> call afterFilter only if beforeFilter succeeds beforeFilter 执行成功调用afterFilter </span><span> 79</span> <span>//</span><span> beforeFilter and afterFilter should be properly nested 两者要配合应用</span> <span> 80</span> $<span>this</span>->owner->on(Controller::EVENT_AFTER_ACTION, [$<span>this</span>, <span>'</span><span>afterFilter</span><span>'</span>], <span>null</span>, <span>false</span><span>); </span><span> 81</span> } <span>else</span><span> { </span><span> 82</span> $<span>event</span>->handled = <span>true</span><span>; </span><span> 83</span> <span> } </span><span> 84</span> <span> } </span><span> 85</span> <span> 86</span> <span>/*</span><span>* </span><span> 87</span> <span> * @param ActionEvent $event </span><span> 88</span> <span>*/</span> <span> 89</span> <span>public</span> function afterFilter($<span>event</span><span>) </span><span> 90</span> <span> { </span><span> 91</span> $<span>event</span>->result = $<span>this</span>->afterAction($<span>event</span>->action, $<span>event</span>-><span>result); </span><span> 92</span> $<span>this</span>->owner->off(Controller::EVENT_AFTER_ACTION, [$<span>this</span>, <span>'</span><span>afterFilter</span><span>'</span><span>]); </span><span> 93</span> <span> } </span><span> 94</span> <span> 95</span> <span>/*</span><span>* </span><span> 96</span> <span> * This method is invoked right before an action is to be executed (after all possible filters.) </span><span> 97</span> <span> * 此方法是在一个动作之前被调用的( </span><span> 98</span> <span> * You may override this method to do last-minute preparation for the action. </span><span> 99</span> <span> * @param Action $action the action to be executed.要执行的动作 </span><span>100</span> <span> * @return boolean whether the action should continue to be executed. </span><span>101</span> <span> * 是否应继续执行该动作。 </span><span>102</span> <span>*/</span> <span>103</span> <span>public</span><span> function beforeAction($action) </span><span>104</span> <span> { </span><span>105</span> <span>return</span> <span>true</span><span>; </span><span>106</span> <span> } </span><span>107</span> <span>108</span> <span>/*</span><span>* </span><span>109</span> <span> * This method is invoked right after an action is executed. </span><span>110</span> <span> * 此方法是在执行动作之后调用的。 </span><span>111</span> <span> * You may override this method to do some postprocessing for the action. </span><span>112</span> <span> * @param Action $action the action just executed. 刚刚执行的动作 </span><span>113</span> <span> * @param mixed $result the action execution result 行动执行结果 </span><span>114</span> <span> * @return mixed the processed action result. 处理结果。 </span><span>115</span> <span>*/</span> <span>116</span> <span>public</span><span> function afterAction($action, $result) </span><span>117</span> <span> { </span><span>118</span> <span>return</span><span> $result; </span><span>119</span> <span> } </span><span>120</span> <span>121</span> <span>/*</span><span>* </span><span>122</span> <span> * Returns a value indicating whether the filer is active for the given action. </span><span>123</span> <span> * 返回一个值,给定的过滤器的行动是否为是积极的。 </span><span>124</span> <span> * @param Action $action the action being filtered 被过滤的动作 </span><span>125</span> <span> * @return boolean whether the filer is active for the given action. </span><span>126</span> <span> * 给定的过滤器的行动是否为是积极的。 </span><span>127</span> <span>*/</span> <span>128</span> <span>protected</span><span> function isActive($action) </span><span>129</span> <span> { </span><span>130</span> <span>if</span> ($<span>this</span>-><span>owner instanceof Module) { </span><span>131</span> <span>//</span><span> convert action uniqueId into an ID relative to the module</span> <span>132</span> $mid = $<span>this</span>->owner-><span>getUniqueId(); </span><span>133</span> $id = $action-><span>getUniqueId(); </span><span>134</span> <span>if</span> ($mid !== <span>''</span> && strpos($id, $mid) === <span>0</span><span>) { </span><span>135</span> $id = substr($id, strlen($mid) + <span>1</span><span>); </span><span>136</span> <span> } </span><span>137</span> } <span>else</span><span> { </span><span>138</span> $id = $action-><span>id; </span><span>139</span> <span> } </span><span>140</span> <span>return</span> !in_array($id, $<span>this</span>->except, <span>true</span>) && (empty($<span>this</span>->only) || in_array($id, $<span>this</span>->only, <span>true</span><span>)); </span><span>141</span> <span> } </span><span>142</span> }

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP中使用clone關鍵字創建對象副本,並通過\_\_clone魔法方法定制克隆行為。 1.使用clone關鍵字進行淺拷貝,克隆對象的屬性但不克隆對象屬性內的對象。 2.通過\_\_clone方法可以深拷貝嵌套對象,避免淺拷貝問題。 3.注意避免克隆中的循環引用和性能問題,優化克隆操作以提高效率。

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。

HTTP緩存頭的關鍵玩家包括Cache-Control、ETag和Last-Modified。 1.Cache-Control用於控制緩存策略,示例:Cache-Control:max-age=3600,public。 2.ETag通過唯一標識符驗證資源變化,示例:ETag:"686897696a7c876b7e"。 3.Last-Modified指示資源最後修改時間,示例:Last-Modified:Wed,21Oct201507:28:00GMT。

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP是一種服務器端腳本語言,用於動態網頁開發和服務器端應用程序。 1.PHP是一種解釋型語言,無需編譯,適合快速開發。 2.PHP代碼嵌入HTML中,易於網頁開發。 3.PHP處理服務器端邏輯,生成HTML輸出,支持用戶交互和數據處理。 4.PHP可與數據庫交互,處理表單提交,執行服務器端任務。

PHP在過去幾十年中塑造了網絡,並將繼續在Web開發中扮演重要角色。 1)PHP起源於1994年,因其易用性和與MySQL的無縫集成成為開發者首選。 2)其核心功能包括生成動態內容和與數據庫的集成,使得網站能夠實時更新和個性化展示。 3)PHP的廣泛應用和生態系統推動了其長期影響,但也面臨版本更新和安全性挑戰。 4)近年來的性能改進,如PHP7的發布,使其能與現代語言競爭。 5)未來,PHP需應對容器化、微服務等新挑戰,但其靈活性和活躍社區使其具備適應能力。

PHP的核心優勢包括易於學習、強大的web開發支持、豐富的庫和框架、高性能和可擴展性、跨平台兼容性以及成本效益高。 1)易於學習和使用,適合初學者;2)與web服務器集成好,支持多種數據庫;3)擁有如Laravel等強大框架;4)通過優化可實現高性能;5)支持多種操作系統;6)開源,降低開發成本。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SublimeText3漢化版
中文版,非常好用

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)