PHP 板


LINE

看板 PHP  RSS
小弟花了很长的时间 才稍微搞懂Composer、namespace、PSR-0 希望这篇文章能帮一些人节省时间 <(_ _)> 网页好读版 http://blog.turn.tw/?p=1122 ----------------------------------- 上次的Composer设计原理与基本用法说明了PHP套件管理的历史与社群提出的解决之道,本 篇文章接着谈类别管理的进阶议题。 当类别名称一样… 当专案大了起来,有时候会有类别名称重复的问题。 假设今天要撰写一个论坛模组,提供讨论区与留言板功能。 你一定很想将讨论区的文章与留言板的文章都命名类别为Article: // BoardArticle.php <?php class Article{ //... } // ForumArticle.php <?php class Article{ //... } 当然了,这麽做会得到一个结果: Fatal error: Cannot redeclare class Article 这种问题有一个简单的解决办法,就是加上前缀字。 类别分别命名为ForumArticle与BoardArticle就可以了。 Q1: 等一下!这个解法好阳春!我看到至少4个问题: 1. 类别名称容易变得冗长。 2. 有些类别一开始你以为不会跟人重复,结果之後真的重复了。 难道永远替类别加前缀字? 3. 类别名称写Article俐落多了!文章就是概念上的文章,不要逼我告诉你是讨论区 还是留言板!如果专案用到两种留言板模组,分别由以前的两个前辈写好, 难道还要逼我把作者名称写进去? class TonyBoardArticle{ //... } class JackBoardArticle{ //... } 4. 如果我在打造框架(framework)呢?几乎会把所有常见名词用过一次(像是Request、 Loader、Response、Controller、Model等类别)! 难道前面全部前缀?看看Codeigniter的原始码,全部用CI_当作前缀。超丑的。 命名空间(namespace)登场 於是PHP从5.3版之後支援了命名空间(namespace)。 所以可以用Article替类别定义了: // BoardArticle.php <?php namespace Board; class Article{ //... } // ForumArticle.php <?php namespace Forum; class Article{ //... } 使用类别时只要加上命名空间即可: //index.php <?php include 'BoardArticle.php'; include 'ForumArticle.php'; $article = new Forum\Article(); $post = new Board\Article(); 如果当前的php档只用到其中一个Article类别, 可以指定当前的php档只用哪个命名空间+类别的组合: <?php include 'BoardArticle.php'; include 'ForumArticle.php'; use Forum\Article; $article = new Article(); $fArticle = new Forum\Article(); $bArticle = new Board\Article(); 如此一来,当php找不到Article类别时,便会去使用use关键字宣告的组合。 当然了,就算用use指定过,原本的宣告方式还是可以用的。(如最下方两行所示) 当东西多了起来… OK,可以继续完成我们的论坛模组了! 讨论区跟留言板有各自的文章,再来还需要「推文」: <?php namespace Board; class Comment{ // ... } <?php namespace Forum; class Comment{ // ... } 使用刚刚学到的命名空间去载入他们: <?php // index.php include 'BoardArticle.php'; include 'ForumArticle.php'; include 'BoardComment.php'; include 'ForumComment.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); // ... 果然是漂亮的各种命名阿! Q2: include有好多行!上次的Composer设计原理与基本用法提到了Composer可以解决这种 问题,当引入命名空间之後,Composer也能发挥作用吗? 是的。 Composer登场 跟上次初学Composer一样,建立一个composer.json档: { "autoload": { "files": [ "ForumArticle.php", "ForumComment.php", "BoardArticle.php", "BoardComment.php" ] } } 注意,上次我们用”classmap”指定资料夹、把资料夹内档案全扫一次,这次我们用” files”分别设定各个档案。 再来,在terminal输入 composer install 执行完毕之後,跟上次一样,只要载入一个档案: <?php require 'vendor/autoload.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); 就可以使用各个类别罗! Q3: 等一下!看起来跟没有命名空间的时候差不多啊! 一样是把php档自动require进去而已? 对啊,你最上面的原始写法,也只是手动载入好几个档案, 在载入的时候本来就没有特别之处: <?php // index.php include 'BoardArticle.php'; include 'ForumArticle.php'; include 'BoardComment.php'; include 'ForumComment.php'; $article = new Forum\Article(); $comment = new Forum\Comment(); // ... 载入php档就只是载入,跟命名空间是两回事。 Q4: 还是不太对啊!上次我用classmap一次把好几个资料夹内容扫过,这次我用files分别 指定每个档案干嘛?Composer不是厉害在能指定资料夹去自动扫过? ……你说的没错。 开个my_lib资料夹,把4个php档都丢进去吧。composer.json这样写就好了: { "autoload": { "classmap": [ "my_lib" ] } } 再来,在terminal输入 composer install 这样就搞定了! 其实我只是想示范,除了用classmap设定资料夹之外,也可以用files直接指定档案。 Q5: OK,原谅你。不过,我必须说,我今天什麽都没学到。最後还是在composer.json写 classmap而已,跟上次一模一样。 是的…我刚说了,载入php档就只是载入,跟命名空间是两回事。 我今天介绍的namespace功能是PHP本身提供的。而Composer只是协助你载入的工具、 当然不可能改变程式语言本身。 Composer只是帮助你少打那一串require而已。 Q6: ㄟ等等…有个地方我觉得很丑。我们现在的my_lib资料夹里面有4个档案,档名很丑: "ForumArticle.php" "ForumComment.php" "BoardArticle.php" "BoardComment.php" 类别名称本身都是俐落的Article跟Comment了,档案名称还是有前缀字。 但也不可能有两个Article.php、两个Comment.php。你有没有办法解决这个美感问题? 这个问题简单,把那个my_lib资料夹删掉,开一个Forum资料夹、一个Board资料夹。 本来的ForumArticle.php改成Article.php丢进Forum资料夹、 本来的BoardArticle.php改成Article.php丢进Board资料夹。 composer.json改写成这样: { "autoload": { "classmap": [ "Board", "Forum" ] } } 再来,在terminal输入 composer install 这招不错吧!档案名称就是类别名称,乾净俐落! 而且资料夹的名字本身就是namespace的名称! 以後都这样做啦!一用到命名空间就开个同名资料夹把档案丢进去! Q7: 这招我觉得还好耶…。本来档案都放在my_lib,我在composer.json只要填my_lib一行 就好,现在变成要填两行。要是我这个论坛模组有一大堆类别、用了一大堆命名空间呢? 那我classmap底下不就要填入好几行?那我宁可全部丢进my_lib,只填my_lib一行! 唔,这样说也是有道理。那重新建立my_lib资料夹,把Board跟Forum资料夹丢进 my_lib资料夹。composer.json改回这样写: { "autoload": { "classmap": [ "my_lib" ] } } 再来,在terminal输入 composer install classmap不只是告诉Composer去载入哪几个资料夹内的档案,还会把资料夹内的 资料夹也全部扫过一次。 怎麽样,Composer够神吧。 Q8: 原来classmap底下会递回扫描下去…。我决定了,我的Forum跟Board都是在 提供线上讨论功能,我决定替我这个模组命名为Discussion。 我要在my_lib底下开Discussion资料夹,然後把原本的Forum跟Board资料夹都丢进去。 你觉得这个想法如何? 还不错。一个Discussion资料夹就是你的整个Discussion模组。 提供了讨论区、留言板功能的Discussion模组,我喜欢。 Q9: 好像忘了什麽…。啊,刚刚说命名空间跟档案结构符合会最漂亮。那我要把那4个档案 的namespace改成这样: <?php namespace Dicussion/Forum; class Article{ //... } 刚刚说了,载入档案就只是载入档案,跟命名空间无关。 现在档案结构没变,所以我应该不用重新输入composer install。 让我试试…。 靠!怎麽喷error了!你骗我? Fatal error: Class 'Discussion\Forum\Comment' not found 呃…,我前面的说法确实有点误导。 PHP自动载入的基本函式长这样: void __autoload ( string $class ) 如你所见,PHP至少需要Composer提供资讯指出$class该去哪个档案找。 namespace改变之後,PHP会找不到对应的$class在哪。 所以还是输入一下composer install吧!Composer会把需要的资讯整理好的。 Q10: OKOK,我知道了,我驾驭这一切了。我觉得这个Dicsussion模组真的超屌的, 不但命名空间漂亮,连档案结构都漂亮。 我要把这个Discussion资料夹整个丢给我朋友,他们公司最近需要论坛模组。 让我打电话给他…。 「什麽?你们已经做好半个论坛模组了?你只需要我模组的其中几个功能? 你们的模组也是放在Discussion资料夹?」 糟糕,资料夹名称重复了!所以我的模组拿给别人还是有不相容的可能,怎麽办? 没有错..还记得你Q1提到的第3个状况吗?确实有把作者名称加进去的必要! 别怕,我教你。你开一个Tony资料夹,把整个Discussion资料夹丢进去。 接着所有档案namespace改成像这样: <?php namespace Tony/Dicussion/Forum; class Article{ //... } 要用的时候就这样喔: <?php require 'vendor/autoload.php'; $article = new Tony\Discussion\Forum\Article(); $comment = new Tony\Discussion\Forum\Comment(); 是变得有点长啦。 但这下搞定了吧!作者名称再撞到的话,就改个独特的名称就是了! 终於。让我们谈谈PSR-0 你一定常听到PSR-0对吧! PSR-0是PHP跨框架相容性统一标准组织订出来的自动载入惯例。 来谈谈PSR-0几个最重要的要求吧! * 命名空间加上类别名称一定要长这样: \<Vendor Name>\(<Namespace>\)*<Class Name> * 前面一定要是作者名称 * 中间可以有任意层次的命名空间、最後是类别名称。 * 中间任意层次的命名空间直接对应到档案结构。 发现了吗?在刚刚Q1~Q10的过程中,其实你已经把PSR-0学完了, 连设计原理都一起搞懂了。 懂这些之後,你也可以做好自己的模组、发布到Packagist给全世界 透过composer下载、使用了! 最後,如果遵守psr-0的话,composer.json可以这样写: { "autoload": { "psr-0": { "Tony\\Discussion\\": "my_lib/" } } } 注意,双引号、两次反斜线并没有特别意思,只是json规定的格式。 跟classmap一样都可以完成任务。两者其实是有差别的…,我们下次再谈。 结语 Composer工具以及PHP-FIG组织的出现, 让一直以来散落各地的PHP社群开始有集中的趋势。 换句话说,各社群终於能共享彼此的library了。 然而,如你所见,psr-0不但导致档案结构容易变得深层,还要求档案结构必须配合程式码 ,这也招致了不少批评。 除此之外,composer autoload内的classmap跟psr-0到底如何分工? 效能差异又为何?这些问题也都还在争论与验证当中。 不过,PSR-0在各框架已被广泛支援,因此建议你还是需要有所了解。 最後… 现在已经出现psr-0的替代方案,称为psr-4。 PSR-0从2014-10-21开始被注明为不建议使用。 至於PSR-4..我们下次再谈。 --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.160.223.112
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/PHP/M.1418226146.A.0AE.html
1F:推 yoyotvyoo: 推 12/10 23:48
2F:推 rickysu: 推 12/11 09:00
3F:推 lucky1lk: 推推 12/11 09:31
4F:推 DJake: 推推推推推 12/11 09:43
5F:推 onininon: 推 12/11 09:51
6F:推 shooliss: 推 12/11 22:20
7F:推 LPH66: 题外话, 其实这种 namespace 的命名规则也是 java package 12/12 09:01
8F:→ LPH66: 建议的命名方式, 因为这些都是可以到处 deploy 的东西 12/12 09:02
9F:→ LPH66: 因此定出来的规则也就大同小异 12/12 09:02
10F:推 aoeeoak: 推,用心写的易於消化 12/13 14:55
11F:推 GTim: 推!有在用,但不是很熟悉…… 12/15 04:23
12F:推 taikobo: 推,问答的方式很活泼,让我想到 Head First 系列 12/16 11:46
13F:推 serinasky: 推 02/23 02:17







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Soft_Job站内搜寻

TOP