看到那个叫『灵剑』的python程序员一派胡言,不光是在答案里,评论里也是拿着自己过期的初级PHP资历在那信口开河,也出来给它来几巴掌。
首先,下面已经有人提到了,亲,你听说过『图灵完备』吗?没听说过的话可以先去维基百科(https://zh.wikipedia.org/wiki/%E5%9C%96%E9%9D%88%E5%AE%8C%E5%82%99%E6%80%A7)补习一下。php和python都是图灵完备的语言,所以没有什么是其中一者能做而另外一个不能做的。
问题回答完毕,下面是说好的打脸时间,也就是来看看『灵剑』所说的所谓的python能做而php所不能做的到底是怎么一回事:
1. 『我原来写PHP的时候主要用的是curl,这是个C的库。不是说它不好,但是你用这个库的话,有一些重要的功能是不行的,比如说我要读取一个URL,然后将返回值作为一个流来处理,读一部分处理一部分』:请阅读手册 PHP: curl_setopt 中的 CURLOPT_FILE,『value should be a stream resource (using fopen(), for example) for the following values of the option parameter』 明确说明了是支持流的。
另外据说你还去看了一大堆第三方的库?不知道guzzle(GitHub – guzzle/guzzle: Guzzle, an extensible PHP HTTP client )这个7000+ star的库不知道你是否看过呢?
2. 『最好这个返回的流还可以像文件一样统一处理,直接用outputStream之类的方法就可以把这个流写到其他语言基本都支持这样的功能,但PHP不行』 同上,上面已经说了,你都fopen了,当然可以像文件一样统一处理
3. 『其他比如说自动复用HTTP/1.1的连接,也是做不到的』废话,你这说的是web server的事情。找apache/nginx去。当然你非要拿php做web server也不是没有,swoole是一个,但你觉得这是c写的扩展不算。那你可以去看看workerman(什么?这也用了c的库所以不算?拜托,系统自带的库你都不让用这也太过分了点吧)。
4. 『运维刚抱怨的来着,别的语言Web服务的前置nginx配置都是统一的,只有PHP,写了一大堆rewrite。就因为PHP不支持按URL匹配规则绑定handler』:你业务糟糕一大堆rewrite怪谁?主流的框架现在基本上都是单入口设计全部rewrite到index.php然后再自己内部分发处理的
5. 『你们老是觉得PHP这个也可以那个也可以,我认为这完全是因为你们要实现的业务太简单了,没见过真正精美的设计。』:同理,你能力太差见识太少,php也是可以去实现你所谓的那些精美的设计的。
6. 『只有你们家PHP是精美设计不好使的,因为语法太死,所以你们只会写面条代码,去读读其他语言比如Python比如Java(Java也比你们强多了),看看他们怎么运用OOP来抽象业务逻辑,怎么运用设计模式,怎么用模块化的方式管理业务功能,怎么提供插件式的扩展,这些你们家PHP一个都做不到。』:PHP: Introduction php5(10多年前了)开始就提供了OOP,至于抽象业务逻辑、运用设计模式、模块化插件化这些不都是程序的事情吗?你能力差怪语言咯?
7. 『我在SAE(新浪云服务)上写了起码三年的PHP,我当年的应用高峰期把SAE跑崩过(就是用fsockopen跑崩的),PHP最恶心的那些问题我全都遇到过。』讲道理那是SAE垃圾怪php?我也跑崩过不止多少次,SAE背地里改了那么多东西能怪PHP?当时向老大推荐了SAE和新浪云商店(好像叫这名字,就是没有写限制的SAE),结果部署上去各种坑啊
8. 『只有你家PHP要区分,第三方扩展只能复制进网站目录里,没有包管理功能,还要小心命名空间冲突,爽不?C扩展装起来费老劲还要改配置文件,爽不?』:php的包管理请参考 Composer 命名空间冲突也顺便解决了。至于C扩展请参考 pecl
9. 『但你们真的想要一个每次用一个类就搜索一遍本地目录的语言吗』:请阅读 psr-0, psr-4 以及 composer的 autoload
10 『自动加载机制是靠在本地目录里查找名称与类名称匹配的文件然后加载没错吧』:你也可以不按规范来,自己实现PHP: spl_autoload 然后你觉得怎么爽就怎么来吧。
11. 『命名空间冲突』:PHP: Using namespaces: Aliasing/Importing
12. 『Java的Web一大支撑就是spring,因为有spring所以能搭建起大规模的、插件式的、可以运用设计模式的Web,PHP不行,这已经是死刑了,说明PHP永远开发不了Java这个规模的Web应用。』:我猜测一下你想说的是IOC吧?这个很多框架也都实现了啊,例如 Service Container ,
顺便说一句,不知道facebook在你眼里,规模是有多小?
槽点太多就不多说了,有些最基础的东西我想说明一下:
首先php就是用C写的,这有什么问题吗?按照你的逻辑只有能完成自举的才能叫语言?
至于每次都要加载一遍,这是与apache/nginx协同工作的方式决定的。把你的问题翻译的稍微专业一些,php能否自己实现web server?答案是肯定的。首先php -S 自带了一个,另外可以参考项目swoole(c实现)、workerman(php实现) 等
附:以下是[灵剑]的回答:
有的不是不能做,是做起来特别恶心,就算用上swoole之类的也一样。多线程支持特别差只是其中之一。
比如说不区分字节流、多字节字符串、unicode字符串,需要在PHP文件里面同时写unicode、utf-8、gbk字符串的时候必须全部用16进制转义,这是一种怎样的令人崩溃的体验……
比如说多返回值,Python可以返回元组然后用简单的语法(a,b = my_func())将元组内容还原到不同变量,PHP只能返回数组,然后写好几行很丑的代码。
PHP能续命到今天主要因为第一能调C的模块,所以依靠C程序员一步一步续上来,swoole也是这样;第二因为PHP程序员普遍素质比较低,写代码的需求范围很狭窄,所以从来没碰到过这个语言的硬边界。
基本上去写一两次Python,你就不会再想重新用回PHP了。PHP的库基本上都是C写,Python的库大部分都是纯Python写,这足够说明两个语言的差距了:同时会PHP和C的宁可写C,同时会Python和C的则愿意写Python。
等什么时候有人用纯PHP写出了OpenStack这样的云计算管理平台,Flask这样的小巧精致的Web框架,Scrapy这样的简单好用的爬虫框架,甚至哪怕是requests这样的HTTP客户端而不是到今天都还在拖着libcurl凑合着用,我们再来谈PHP不能做到什么。
忍不住了,那个灵剑的python码农,之前也在黑php的问题下看你瞎回答。黑php没问题我也常常黑,可是你的关于php回答简直不懂装懂还瞎说,这里把你的回答一句一句。
1、”多线程支持特别差只是其中之一。”这么说吧,php、ruby、python等这些比较主流的脚本语言里面论多线程支持,php是做得最好的。py和ruby支持多线程偷工减料加全局锁弄了个假的多线程,php本身改造了语言核心分了线程安全和非线程安全版本,php的多线程是真的多线程。其实脚本语言作为高级语言多线程并不鲁棒所以我基本不用多线程特性,要用多线程任务我还是倾向于用java/c++静态类型语言。
2、“比如说不区分字节流、多字节字符串、unicode字符串,需要在PHP文件里面同时写unicode、utf-8、gbk字符串的时候必须全部用16进制转义,这是一种怎样的令人崩溃的体验”。用python没被编码灾难的恶心过的有几个?我用php基本没有为编码问题操心过。你说为毛不用py3?是啊,py3傻逼的不兼容py2给第三方库社区带来了多大的麻烦,ubuntu16.04才敢升py3的吧,对不起大部分的生产环境centos6还py2.7呢。
3、“比如说多返回值,Python可以返回元组然后用简单的语法(a,b = my_func())将元组内容还原到不同变量,PHP只能返回数组,然后写好几行很丑的代码。”php不只能返回数组,还能返回对象等等,不过我相信你的意思是php没有py那样的语法糖。语法糖这东西我不是很care,也是用的时候才去查,你说的这个特性php里似乎有:$my_array = array(“Dog”,”Cat”,”Horse”);list($a, $b, $c) = $my_array;不过这根本不重要。
4、“PHP能续命到今天主要因为第一能调C的模块,所以依靠C程序员一步一步续上来,swoole也是这样;”php把cpu密集型函数写成c模块就是为了性能啊,这有啥可黑的?php7最棒的特性也是在尽量兼容的前提下提升性能:https://pages.zend.com/rs/zendtechnologies/images/PHP7-Performance%20Infographic.pdf。就我的判断而言,php语言和社区发展很好。
5、“第二因为PHP程序员普遍素质比较低,写代码的需求范围很狭窄,所以从来没碰到过这个语言的硬边界。基本上去写一两次Python,你就不会再想重新用回PHP了。”你这样地图炮是不对的,每个语言都有每个语言的使用场景,我原来写py挺多的,但是web相关的我觉得php更好用。
6、“等什么时候有人用纯PHP写出了OpenStack这样的云计算管理平台,Flask这样的小巧精致的Web框架,Scrapy这样的简单好用的爬虫框架,甚至哪怕是requests这样的HTTP客户端而不是到今天都还在拖着libcurl凑合着用,我们再来谈PHP不能做到什么。”OpenStack没用过不便评价,Flask这边组里一直在用在遇到性能问题后重构转java了,Scapy和requests你张口就来我今天就用这个2打你脸。Scrapy作为一个爬虫框架基本上写几个配置文件就可以跑了,但是爬虫的本质是开一个httpclient取回html+dom操作抽取数据,Scrapy封装的很厉害适合初学者改几个参数就跑起来了,但是扩展特别差。这边搞爬虫的py码农在要完成需要特别定制的爬虫都是直接开requests回来beautifulsoup抽数据的。requests这个httpclient是挺好用的,php的httpclient也并不只有libcurl,比较大的库的话guzzle也很好用,而且有很棒的异步支持。我用guzzle可以使用libevent的事件库单进程只开一个guzzle的httpclient并发同时异步爬100个网站,而requests并没有异步支持。
———————————————————————
看了Coldwings的针对我的比较有水平的回答,我兴致顿时来了,这里回应如下:
1、关于编码问题我相信已经讨论的足够清楚了,我觉得你说的也有道理,感性的东西这里就不回应了。
2、py下的异步并发方案我之前调研过很久的,grequests(GitHub – kennethreitz/grequests: Requests + Gevent = <3)是对gevent的很薄的包装,star很多但代码150行不到,实际上不怎么好用。
3、协程本质上是把异步用同步的方式来写,所以协程并不是说在并发上比异步强。
4、并不是只有Scrapy能调度phantomjs(你可以把phantomjs集成到任何爬虫里面),实际上我有在php下并发驱动phantomjs的一些经验(单机i7并发驱动80个phantomjs实例,包括并发下缓存、代理、资源泄漏和headless开发困难等各种坑的对应处理),我相信用py来驱动phantomjs也差不多,看你用啥顺手。
5、爬虫这块你所谓的分布式是指多机并发爬取的话,我用redis比较多,当然了我机器不多。我自己用php写了基于redis的多节点并发爬虫方案,有个爬虫2台PC并发最多150个phantomjs+150个guzzle的httpclient吧。多爬虫协作和任务分发啥的,比起专门的消息队列我比较推荐redis,因为redis的单机10w的qps在满足爬虫并发的同时,还有非常好用的5种数据结构,对爬虫的调度、状态查看、参数动态设置都有很大帮助。
6、我爬虫并发100是http并发不是tcp并发,我用php在单进程单httpclient下在低cpu低内存下异步并发跑满了小水管。线程池方案和异步并发方案优劣我认为已经讨论的足够清楚了(另外我真的觉得我的基于guzzle的单httpclient异步多并发的爬虫方案很不错的诶,我对这个很自满的。如果你感兴趣的话可以看看我的两篇博客讨论的这个问题:谈谈爬虫的并发问题和redis使用心得+高并发httpclient的理解)。
7、python的并发http方案我也之前也调查过(What is the fastest way to send 100,000 HTTP requests in Python?),里面也有你提到的grequests和tornado的那个异步httpclient。tornado的那个异步的httpclient恰恰是基于libcurl的(tornado.httpclient)而且没有并发支持的,而php的guzzle默认是libcurl但是你可以选择别的事件库比如libevent的,guzzle可是支持异步并发的哦(在py和java下我找了一段时间都没找到这样的httpclient的)。
评论