Yii2 advanced版API接口开发 基于RESTful架构的 配置、实现、测试
环境配置:
开启服务器伪静态
本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码
LoadModule rewrite_module modules/mod_rewrite.so
将其前面的#去掉,如果没有找到则添加进去。
找到一下代码
<directory><span> AllowOverride All Options None </span><span>Require</span><span> all granted </span></directory>
将原本的AllowOverride None改为AllowOverride All。
然后在站点根目录下创建一个.htaccess文件,内容如下:


<ifmodule mod_rewrite.c><span> Options </span>+<span>FollowSymlinks RewriteEngine On RewriteCond </span>%{REQUEST_FILENAME} !-<span>d RewriteCond </span>%{REQUEST_FILENAME} !-<span>f RewriteRule </span>. index.<span>php </span></ifmodule>
此处不再赘述yii2的配置,如果需要可以看YII2实战手册。
YII2实际操作:
1、配置URL规则及modules
(1)新建modules文件夹,实行api接口版本控制。例如V1版本、V2版本……
在v1文件夹下新建controllers文件夹(控制器)、models文件夹(模型)、Module.php配置文件。
Module.php文件如下:
<span> 1</span> <span>php </span><span> 2</span><span>namespace api\modules\v1; </span><span> 3</span><span> 4</span><span>class</span> Module <span>extends</span><span> \yii\base\Module </span><span> 5</span><span>{ </span><span> 6</span><span> 7</span><span>public</span><span>$controllerNamespace</span> = 'api\modules\v1\controllers'<span>; </span><span> 8</span><span> 9</span><span>public</span><span>function</span><span> init() </span><span>10</span><span> { </span><span>11</span> parent::<span>init(); </span><span>12</span><span> } </span><span>13</span> }
第2行和第7行随版本扩展而变化(v1->v2...)。
(2)配置config文件夹下的main.php文件


<span> 1</span> <span>php </span><span> 2</span><span>$params</span> = <span>array_merge</span>(<span>require</span> (__DIR__ . '/../../common/config/params.php'), <span>require</span> (__DIR__ . '/../../common/config/params-local.php'), <span>require</span> (__DIR__ . '/params.php'), <span>require</span> (__DIR__ . '/params-local.php'<span>)); </span><span> 3</span><span> 4</span><span>return</span><span> [ </span><span> 5</span> 'id' => 'app-api', <span> 6</span> 'basePath' => <span>dirname</span>(__DIR__), <span> 7</span> 'bootstrap' =><span> [ </span><span> 8</span> 'log' <span> 9</span> ], <span>10</span> 'modules' =><span> [ </span><span>11</span> 'v1' =><span> [ </span><span>12</span> 'class' => 'api\modules\v1\Module' <span>13</span> ], <span>14</span> 'v2' =><span> [ </span><span>15</span> 'class' => 'api\modules\v2\Module' <span>16</span><span> ] </span><span>17</span> ], <span>18</span> 'controllerNamespace' => 'api\controllers', <span>19</span> 'components' =><span> [ </span><span>20</span> 'user' =><span> [ </span><span>21</span> 'identityClass' => 'common\models\User', <span>22</span> 'enableAutoLogin' => <span>false</span>, <span>23</span> 'enableSession' => <span>false</span>, <span>24</span> 'loginUrl' => <span>null</span><span>25</span> ], <span>26</span> 'urlManager' =><span> [ </span><span>27</span> 'enablePrettyUrl' => <span>true</span>, <span>//</span><span> 启用美化URL</span><span>28</span> 'enableStrictParsing' => <span>true</span>, <span>//</span><span> 是否执行严格的url解析</span><span>29</span> 'showScriptName' => <span>false</span>, <span>//</span><span> 在URL路径中是否显示脚本入口文件</span><span>30</span> 'rules' =><span> [ </span><span>31</span><span> [ </span><span>32</span> 'class' => 'yii\rest\UrlRule', <span>33</span> 'controller' =><span> [ </span><span>34</span> 'v1/site' <span>35</span><span> ] </span><span>36</span> ], <span>37</span><span> [ </span><span>38</span> 'class' => 'yii\rest\UrlRule', <span>39</span> 'controller' =><span> [ </span><span>40</span> 'v2/site' <span>41</span><span> ] </span><span>42</span><span> ] </span><span>43</span><span> ] </span><span>44</span> ], <span>45</span> 'log' =><span> [ </span><span>46</span> 'traceLevel' => YII_DEBUG ? 3 : 0, <span>47</span> 'targets' =><span> [ </span><span>48</span><span> [ </span><span>49</span> 'class' => 'yii\log\FileTarget', <span>50</span> 'levels' =><span> [ </span><span>51</span> 'error', <span>52</span> 'warning' <span>53</span><span> ] </span><span>54</span><span> ] </span><span>55</span><span> ] </span><span>56</span> ], <span>57</span> 'errorHandler' =><span> [ </span><span>58</span> 'errorAction' => 'site/error' <span>59</span><span> ] </span><span>60</span> ], <span>61</span> 'params' => <span>$params</span><span>62</span> ];
注意10~17行、20~44行的组件配置,相信大家仔细阅读就能明白,此处不再赘述原理,请大家尤其注意33~35行的代码,此处表示的是v1/site控制器,随着接口控制器的增多,可以直接在数组中增加即可。本文力求快速配置出RESTful架构的实现。
(3)v2、v3表示以后的版本变化,配置都类似于v1文件夹。
2、创建一个模型
数据库准备一个名为mxq_guide的数据表
<span>CREATE TABLE `mxq_guide` ( `id` int(</span>11) NOT <span>NULL</span> AUTO_INCREMENT,<span> `imgurl` varchar(</span>255) <span>DEFAULT</span><span>NULL </span>COMMENT '图片路径'<span>,</span><span><br> `status` int(</span><span>11) </span><span>DEFAULT</span><span>NULL</span><span> COMMENT '1启用 0禁用',<br></span><span> `flag` int(</span><span>11) </span><span>DEFAULT</span><span>NULL</span><span> COMMENT '1安卓 2苹果',</span><span><br> PRIMARY </span><span>KEY</span><span> (`id`) <br> ) ENGINE</span><span>=MyISAM AUTO_INCREMENT=24 </span><span>DEFAULT</span><span> CHARSET=utf8 COMMENT='APP导航图';</span>
创建后请注意及时往数据库添加几条数据信息。
通过脚手架gii来创建guide.php模型(使用方法请看yii2权威指南)。生成后的文件注意改写,修改为如下形式以满足RESTful的需求。之后从models文件夹中转移到v1/models文件夹中,并注意命名空间的修改。


<span> 1</span> <span>php </span><span> 2</span><span>namespace api\modules\v1\models; </span><span> 3</span><span> 4</span><span>use</span><span> Yii; </span><span> 5</span><span>use</span><span> yii\db\ActiveRecord; </span><span> 6</span><span>use</span><span> yii\web\IdentityInterface; </span><span> 7</span><span> 8</span><span>/*</span><span>* </span><span> 9</span><span> * This is the model class for table "{{%guide}}". </span><span>10</span><span> * </span><span>11</span><span> * @property integer $id </span><span>12</span><span> * @property string $imgurl </span><span>13</span><span> * @property integer $status </span><span>14</span><span> * @property integer $flag </span><span>15</span><span>*/</span><span>16</span><span>class</span> Guide <span>extends</span> ActiveRecord <span>implements</span><span> IdentityInterface </span><span>17</span><span>{ </span><span>18</span><span>19</span><span>public</span><span>static</span><span>function</span> findIdentityByAccessToken(<span>$token</span>, <span>$type</span> = <span>null</span><span>) </span><span>20</span><span> { </span><span>21</span><span>return</span><span>static</span>::<span>findOne([ </span><span>22</span> 'access_token' => <span>$token</span><span>23</span><span> ]); </span><span>24</span><span> } </span><span>25</span><span>26</span><span>public</span><span>function</span><span> getId() </span><span>27</span><span> { </span><span>28</span><span>return</span><span>$this</span>-><span>id; </span><span>29</span><span> } </span><span>30</span><span>31</span><span>public</span><span>function</span><span> getAuthKey() </span><span>32</span><span> { </span><span>33</span><span>return</span><span>$this</span>-><span>authKey; </span><span>34</span><span> } </span><span>35</span><span>36</span><span>public</span><span>function</span> validateAuthKey(<span>$authKey</span><span>) </span><span>37</span><span> { </span><span>38</span><span>return</span><span>$this</span>->authKey === <span>$authKey</span><span>; </span><span>39</span><span> } </span><span>40</span><span>41</span><span>public</span><span>static</span><span>function</span> findIdentity(<span>$id</span><span>) </span><span>42</span><span> { </span><span>43</span><span>return</span><span>static</span>::findOne(<span>$id</span><span>); </span><span>44</span><span> } </span><span>45</span><span>46</span><span>public</span><span>static</span><span>function</span><span> tableName() </span><span>47</span><span> { </span><span>48</span><span>return</span> '{{%guide}}'<span>; </span><span>49</span><span> } </span><span>50</span><span>51</span><span>public</span><span>function</span><span> rules() </span><span>52</span><span> { </span><span>53</span><span>return</span><span> [ </span><span>54</span><span> [ </span><span>55</span><span> [ </span><span>56</span> 'imgurl', <span>57</span> 'status', <span>58</span> 'flag' <span>59</span> ], <span>60</span> 'required' <span>61</span> ], <span>62</span><span> [ </span><span>63</span><span> [ </span><span>64</span> 'status', <span>65</span> 'flag' <span>66</span> ], <span>67</span> 'integer' <span>68</span> ], <span>69</span><span> [ </span><span>70</span><span> [ </span><span>71</span> 'imgurl' <span>72</span> ], <span>73</span> 'string', <span>74</span> 'max' => 255 <span>75</span><span> ] </span><span>76</span><span> ]; </span><span>77</span><span> } </span><span>78</span><span>79</span><span>public</span><span>function</span><span> attributeLabels() </span><span>80</span><span> { </span><span>81</span><span>return</span><span> [ </span><span>82</span> 'id' => Yii::t('app', 'ID'), <span>83</span> 'imgurl' => Yii::t('app', 'imgurl'), <span>84</span> 'status' => Yii::t('app', 'status'), <span>85</span> 'flag' => Yii::t('app', 'flag'<span>) </span><span>86</span><span> ]; </span><span>87</span><span> } </span><span>88</span> }
3、创建一个控制器


<span> 1</span> <span>php </span><span> 2</span><span>namespace api\modules\v1\controllers; </span><span> 3</span><span> 4</span><span>use</span><span> Yii; </span><span> 5</span><span>use</span><span> yii\rest\ActiveController; </span><span> 6</span><span>use</span><span> yii\filters\auth\CompositeAuth; </span><span> 7</span><span>use</span><span> yii\filters\auth\QueryParamAuth; </span><span> 8</span><span>use</span><span> yii\data\ActiveDataProvider; </span><span> 9</span><span>10</span><span>class</span> SiteController <span>extends</span><span> ActiveController </span><span>11</span><span>{ </span><span>12</span><span>13</span><span>public</span><span>$modelClass</span> = 'api\modules\v1\models\guide'<span>; </span><span>14</span><span>15</span><span>public</span><span>$serializer</span> =<span> [ </span><span>16</span> 'class' => 'yii\rest\Serializer', <span>17</span> 'collectionEnvelope' => 'items' <span>18</span><span> ]; </span><span>19</span><span>20</span><span>//</span><span> public function behaviors() </span><span>21</span><span> // { </span><span>22</span><span> // $behaviors = parent::behaviors(); </span><span>23</span><span> // $behaviors['authenticator'] = [ </span><span>24</span><span> // 'class' => CompositeAuth::className(), </span><span>25</span><span> // 'authMethods' => [ </span><span>26</span><span> // QueryParamAuth::className() </span><span>27</span><span> // ] </span><span>28</span><span> // ]; </span><span>29</span><span> // return $behaviors; </span><span>30</span><span> // }</span><span>31</span><span>public</span><span>function</span><span> actions() </span><span>32</span><span> { </span><span>33</span><span>$actions</span> = parent::<span>actions(); </span><span>34</span><span>//</span><span> 注销系统自带的实现方法</span><span>35</span><span>unset</span>(<span>$actions</span>['index'], <span>$actions</span>['update'], <span>$actions</span>['create'], <span>$actions</span>['delete'], <span>$actions</span>['view'<span>]); </span><span>36</span><span>return</span><span>$actions</span><span>; </span><span>37</span><span> } </span><span>38</span><span>39</span><span>public</span><span>function</span><span> actionIndex() </span><span>40</span><span> { </span><span>41</span><span>$modelClass</span> = <span>$this</span>-><span>modelClass; </span><span>42</span><span>$query</span> = <span>$modelClass</span>::<span>find(); </span><span>43</span><span>return</span><span>new</span><span> ActiveDataProvider([ </span><span>44</span> 'query' => <span>$query</span><span>45</span><span> ]); </span><span>46</span><span> } </span><span>47</span><span>48</span><span>public</span><span>function</span><span> actionCreate() </span><span>49</span><span> { </span><span>50</span><span>$model</span> = <span>new</span><span>$this</span>-><span>modelClass(); </span><span>51</span><span>//</span><span> $model->load(Yii::$app->getRequest() </span><span>52</span><span> // ->getBodyParams(), '');</span><span>53</span><span>$model</span>->attributes = Yii::<span>$app</span>->request-><span>post(); </span><span>54</span><span>if</span> (! <span>$model</span>-><span>save()) { </span><span>55</span><span>return</span><span>array_values</span>(<span>$model</span>->getFirstErrors())[0<span>]; </span><span>56</span><span> } </span><span>57</span><span>return</span><span>$model</span><span>; </span><span>58</span><span> } </span><span>59</span><span>60</span><span>public</span><span>function</span> actionUpdate(<span>$id</span><span>) </span><span>61</span><span> { </span><span>62</span><span>$model</span> = <span>$this</span>->findModel(<span>$id</span><span>); </span><span>63</span><span>$model</span>->attributes = Yii::<span>$app</span>->request-><span>post(); </span><span>64</span><span>if</span> (! <span>$model</span>-><span>save()) { </span><span>65</span><span>return</span><span>array_values</span>(<span>$model</span>->getFirstErrors())[0<span>]; </span><span>66</span><span> } </span><span>67</span><span>return</span><span>$model</span><span>; </span><span>68</span><span> } </span><span>69</span><span>70</span><span>public</span><span>function</span> actionDelete(<span>$id</span><span>) </span><span>71</span><span> { </span><span>72</span><span>return</span><span>$this</span>->findModel(<span>$id</span>)-><span>delete(); </span><span>73</span><span> } </span><span>74</span><span>75</span><span>public</span><span>function</span> actionView(<span>$id</span><span>) </span><span>76</span><span> { </span><span>77</span><span>return</span><span>$this</span>->findModel(<span>$id</span><span>); </span><span>78</span><span> } </span><span>79</span><span>80</span><span>protected</span><span>function</span> findModel(<span>$id</span><span>) </span><span>81</span><span> { </span><span>82</span><span>$modelClass</span> = <span>$this</span>-><span>modelClass; </span><span>83</span><span>if</span> ((<span>$model</span> = <span>$modelClass</span>::findOne(<span>$id</span>)) !== <span>null</span><span>) { </span><span>84</span><span>return</span><span>$model</span><span>; </span><span>85</span> } <span>else</span><span> { </span><span>86</span><span>throw</span><span>new</span> NotFoundHttpException('The requested page does not exist.'<span>); </span><span>87</span><span> } </span><span>88</span><span> } </span><span>89</span><span>90</span><span>public</span><span>function</span> checkAccess(<span>$action</span>, <span>$model</span> = <span>null</span>, <span>$params</span> =<span> []) </span><span>91</span><span> { </span><span>92</span><span>//</span><span> 检查用户能否访问 $action 和 $model </span><span>93</span><span> // 访问被拒绝应抛出ForbiddenHttpException </span><span>94</span><span> // var_dump($params);exit;</span><span>95</span><span> } </span><span>96</span> }
控制器请创建在modules/controllers文件夹下,并注意命名空间的修改。
要注意的是,此处的控制器与普通的控制器继承Controller不同,此处需继承ActiveController类。
20~30行注释的代码是基于RESTful架构的access_token认证,目前还未测试通过,后续补充。
至此,基于YII2的所有配置已基本完成,接下来介绍api接口测试工具及方法。
RESTful的测试工具PostMAN:
首先介绍一下postman这款插件,是基于谷歌浏览器的一款模拟请求的实用插件。具体使用,在下面测试过程中涉及截图,介绍不足之处请见谅,自己也是第一次使用。
推荐使用上面的APP版本,便于后续封装自己写好的api接口,下面的是网页版本。
YII2支持的RESTful有四种请求方式:GET查看信息,POST创建信息,PUT更新信息,DELETE删除信息。
下面开始演示四种请求数据的方式。(只是截图演示效果,具体使用还需要大家自己去摸索。)
此处演示的是GET方法请求数据库的数据。对应的是modules/controllers/SiteController/actionIndex方法。
请大家注意最上面方框内的URL地址,rest默认将控制器进行复数请求http://api.mxq.com/v1/sites,此处就是rest的默认规则。
打*星号位置显示的是正常的效果,如若出现错误,大家可以去YII权威指南——错误检查错误原因。
YII2的ActiveController默认实现了数据的分页效果。
此处演示的是POST方法新建数据库的数据。对应的是modules/controllers/SiteController/actionCreate方法。
如果在数据库的数据层写好数据校验规则,此处提交数据不满足要求的时候就会显示相应的错误。这也是REST的优势之一。比如如下情况,flag我定义的是int型:
接下来演示的是PUT方法更新数据库的数据。对应的是modules/controllers/SiteController/actionUpdate方法。
此处请大家再次注意最上面的URL:http://api.mxq.com/v1/sites/15 此处15代表的是数据库id为15的数据,表示更新数据库ID为15的数据信息。请大家一定注意。RESTful在使用更新和删除数据操作的时候,id不能一表单的形式提交,必须紧跟在URL之后。
接下来演示的是DELETE方法删除数据库的数据。对应的是modules/controllers/SiteController/actionDelete方法。
当返回值为1的时候表示的就是删除操作执行成功。具体原理请大家仔细观察sitecontroller控制器内的函数。
以上就是基于yii2的RESTful的一些简单介绍、实现方法以及测试结果。有什么不正确或遗漏的地方,欢迎大家来补充。后续也会在此基础上进行更新。本人第一次接触yii2框架和RESTful架构,表述如有不对之处,请大家见谅。
以上就介绍了Yii2 advanced版API接口开发 基于RESTful架构的 配置、实现、测试,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

De nombreux utilisateurs choisiront la marque Huawei lors du choix des montres intelligentes. Parmi eux, les Huawei GT3pro et GT4 sont des choix très populaires. De nombreux utilisateurs sont curieux de connaître la différence entre Huawei GT3pro et GT4. Quelles sont les différences entre Huawei GT3pro et GT4 ? 1. Apparence GT4 : 46 mm et 41 mm, le matériau est un miroir en verre + un corps en acier inoxydable + une coque arrière en fibre haute résolution. GT3pro : 46,6 mm et 42,9 mm, le matériau est du verre saphir + corps en titane/corps en céramique + coque arrière en céramique 2. GT4 sain : en utilisant le dernier algorithme Huawei Truseen5.5+, les résultats seront plus précis. GT3pro : ajout d'un électrocardiogramme ECG, d'un vaisseau sanguin et de la sécurité

Pourquoi l'outil Snipping ne fonctionne pas sous Windows 11 Comprendre la cause première du problème peut aider à trouver la bonne solution. Voici les principales raisons pour lesquelles l'outil de capture peut ne pas fonctionner correctement : L'assistant de mise au point est activé : cela empêche l'ouverture de l'outil de capture. Application corrompue : si l'outil de capture plante au lancement, il est peut-être corrompu. Pilotes graphiques obsolètes : des pilotes incompatibles peuvent interférer avec l'outil de capture. Interférence provenant d'autres applications : d'autres applications en cours d'exécution peuvent entrer en conflit avec l'outil de capture. Le certificat a expiré : une erreur lors du processus de mise à niveau peut provoquer ce problème. Solution simple. Celles-ci conviennent à la plupart des utilisateurs et ne nécessitent aucune connaissance technique particulière. 1. Mettez à jour les applications Windows et Microsoft Store

Partie 1 : étapes de dépannage initiales Vérification de l'état du système Apple : avant d'aborder des solutions complexes, commençons par les bases. Le problème ne vient peut-être pas de votre appareil ; les serveurs Apple sont peut-être en panne. Visitez la page État du système d'Apple pour voir si l'AppStore fonctionne correctement. S'il y a un problème, tout ce que vous pouvez faire est d'attendre qu'Apple le résolve. Vérifiez votre connexion Internet : assurez-vous que vous disposez d'une connexion Internet stable, car le problème "Impossible de se connecter à l'AppStore" peut parfois être attribué à une mauvaise connexion. Essayez de basculer entre le Wi-Fi et les données mobiles ou de réinitialiser les paramètres réseau (Général > Réinitialiser > Réinitialiser les paramètres réseau > Paramètres). Mettez à jour votre version iOS :

Après que des problèmes soient survenus dans de nombreuses bourses centralisées, de plus en plus d’investisseurs en cryptomonnaies ont commencé à transférer des actifs vers des portefeuilles froids afin de réduire les risques posés par les bourses centralisées. Cet article présente Trezor, le premier fournisseur de portefeuilles froids au monde. Depuis le lancement du premier portefeuille froid en 2014, il a été vendu dans de nombreux pays du monde. Les produits de Trezor incluent le Model One lancé en 2014 et la version avancée Model T lancée en 2018. Ce qui suit continuera à présenter les différences entre ces deux produits et les autres portefeuilles froids. Qu'est-ce que le portefeuille froid Trezor ? En 2014, Trezor a lancé le premier portefeuille froid ModelOne. En plus des devises courantes BTC, ETH, USDT et autres, le portefeuille prend également en charge plus de 1 000 autres devises.

À mesure qu’Internet continue de se développer, la demande de développement d’applications Web augmente également. Pour les développeurs, le développement d'applications nécessite un cadre stable, efficace et puissant, qui peut améliorer l'efficacité du développement. Yii est un framework PHP hautes performances de premier plan qui offre des fonctionnalités riches et de bonnes performances. Yii3 est la version nouvelle génération du framework Yii, qui optimise davantage les performances et la qualité du code basé sur Yii2. Dans cet article, nous présenterons comment utiliser le framework Yii3 pour développer des applications PHP.

php提交表单通过后,弹出的对话框怎样在当前页弹出php提交表单通过后,弹出的对话框怎样在当前页弹出而不是在空白页弹出?想实现这样的效果:而不是空白页弹出:------解决方案--------------------如果你的验证用PHP在后端,那么就用Ajax;仅供参考:HTML code

Avec le développement continu de la technologie du cloud computing, la sauvegarde des données est devenue quelque chose que chaque entreprise doit faire. Dans ce contexte, il est particulièrement important de développer un système de sauvegarde cloud hautement disponible. Le framework PHP Yii est un framework puissant qui peut aider les développeurs à créer rapidement des applications Web hautes performances. Ce qui suit explique comment utiliser le framework Yii pour développer un système de sauvegarde cloud hautement disponible. Conception du modèle de base de données Dans le framework Yii, le modèle de base de données est une partie très importante. Parce que le système de sauvegarde des données nécessite beaucoup de tables et de relations

À l’ère actuelle de l’information, le big data, l’intelligence artificielle, le cloud computing et d’autres technologies sont devenus au centre des préoccupations des grandes entreprises. Parmi ces technologies, la technologie de rendu des cartes graphiques, en tant que technologie de traitement graphique haute performance, fait l'objet de plus en plus d'attention. La technologie de rendu des cartes graphiques est largement utilisée dans le développement de jeux, les effets spéciaux de films et de télévision, la modélisation technique et d'autres domaines. Pour les développeurs, choisir un framework adapté à leurs projets est une décision très importante. Parmi les langages actuels, PHP est un langage très dynamique. Quelques excellents frameworks PHP comme Yii2, Ph.
