javascript教程从5个方面全面解析PHP的糟糕设计
2012-04-27 21:42 linux svn 命令 mac svn svn merge 阅读(208) 评论(0) 收藏 举报PHP不仅使用起来尴尬,还有要嘛我想要的不适合,要嘛不是最令人满意,要嘛我的.我可以告诉你关于一门语言,所有我想避免的好方式,所有我喜欢的坏方式.来吧,问吧!谈话会很有趣!
AD:
注:这篇文章很长,而且可能读起来很乱,很难懂
前言
我的脾气古怪.我会抱怨很多东西.这个星球上大多数技术我都不喜欢.
PHP不仅使用起来尴尬,还有要嘛我想要的不适合,要嘛不是最令人满意,要嘛我的.我可以告诉你关于一门语言,所有我想避免的好方式,所有我喜欢的坏方式.来吧,问吧!谈话会很有趣!
php是唯一的例外.几乎php抽象的所有东西都是的.包括语言,框架,整个生态系统都一塌糊涂.我几乎不能单独列出的事情,因为它都坏了.每次我打算编辑一堆杂乱如麻的php抱怨清单的时候,我都被一些琐事打乱,越深入就越会发现其它令人的事情.
php让人难堪.它是如此的破碎,但那些被培训的业余爱好者,却对它称赞不已.php在做一些徽不足道的措施,但我选择忘记它.
不过我得让我的系统摆脱这些东西,也就这样了,这是最后一次尝试.
打个比喻
我只是随口和Mel抱怨下,而她却让我发表出来.
我甚至说不出来PHP到底怎么了,因为--还好.想想你有一个,嗯,工具箱吧.一堆工具.看起来还好,有标准的东西.
你拔除螺丝钉,它怪异的有三个头.OK,好吧,这对你不太有用,但你猜迟早有天会有用.
你拿出榔头,被震住了,两边都有是尖爪.但它仍然能用,我的意思是,你可以用两头的中部斜着敲.
你拿出老虎钳,但它们没有锯齿面.表面平而光滑.这没多大用,但依然能用,没什么.
你可以继续.工具箱的东西都是怪异和琢磨不定的,但又不能说毫无价值.整体看没什么大问题;它的工具都齐全.
现在,想象有很多使用这些工具的木匠,它们和你说:"这些工具有什么问题呢?我们都用过,它们工作都很好啊!".工匠们给你展示他们建的房子,每个门都是五边形的而屋顶是癫倒的.你敲前门,它向内倒榻了,而他们却抱怨你打破了他们的门.
这就是PHP的问题.
立场
我认为下面的特质对于一门语言的生产力和可用性是重要的,而PHP在大范围它们.如果你不同意这些,好吧,我无法想像,我们永远不会达成一致.
>>一门语言必须是可预见的.它是將人类的思想反映给计算机执行的媒介,因此它的关键是,人类对程序的理解实际要正确.
>>语言必须一致.相似的东西就要看起来相似,不同的就是不同.学习了语言的部分知识,就应能很容易理解剩下的部分.
>>语言必须简洁.新语言应该减少继承旧语言的不好的形式.(我们也可以写机器码.)新语言当然应努力避免织入新的特有的形式.
>>语言必须是可靠的.语言是解决问题的工具;应尽量避免引入新问题.任何"陷阱"都会大量的分散注意力.
>>语言必须是可调试的.当出错的时候,程序员必须修正它,我们需要获得我们想要的帮助.
我的立场是:
>>PHP到处处充满惊奇:mysql_real_escape_string,E_ACTUALLY_ALL
>>PHP不一致:strpos,str_rot13
>>PHP需要特别形式:error-checkingaroundCAPIcalls,===
>>PHP古怪:==.for($fooas&$bar)
>>PHP晦涩:默认无栈或tals,复杂的错误报告
我不能就单个问题解释为什么它归为这些类,否则將会没完没了.我相信读者自己会思考.
不要再和我扯这些东西了
我知道很多有利的论点.我也听到很多反驳的论点.这些都只能让谈话立即停止.不要再跟我扯这些东西了,求你了.:(
>>不要和我说"好的开发者能用任何语言写出好的代码",或者坏开发者..吧啦吧啦.这毫无意义.好的工匠可以用石头或锤子驾驭钉子,但你见过有多少工匠用石头的?成为一个好开发者的标准之一就是善于选择工具.
>>不要和我说熟记上千个例外和古怪行为是开发者的职责.是的,这在任何系统中都是必要的,因为电脑是傻的.这不意味着,系统能疯狂的接受而没有上限.PHP有的只是异常,这是不行的,一旦和语言摔角决斗,你实际编写程序就要花费更多的努力.我的工具不能为我创建应用产生积极作用.
>>不要和我说"那就是CAPI的工作方式".这星球上高级语言存在的目的是什么,它们能提供的一切仅仅是一些字符串助手函数和一堆C的包装器?如果是这样,那就用C!这里,甚至还有为它准备的CGI库.
>>不要和我扯"搞出奇怪的事,是你活该".如果存在两个特性,总有一天,某些人会找到一起使用它们的理由.再次强调,这不是C;这里没有规范,这里不需要"未定义行为".
>>不要再和我扯Facebook和Wikipedia就用的PHP.我早知道了!它们也能用Brain写,但只要他们足够陪明,不断这些事情,他们总能克服平台的问题.众所周知,javascript教程从5个方面全面解析PHP的糟糕设计如果使用其它语言编写,开发时间可能会减少一半或加倍;单独拿出这些数据毫无意义.
,不要再和我扯任何东西了!如果列出的没有你的PHP的观点,无所谓,因此请停止在网上做无意义的争论,继续开发高帅富酷的站点来证明我是错的:).
偷偷告诉你:我非常喜欢Python.我也很乐意对它说些你不爱听的话,如果你真想的话.我并不要求它完美;我只是想扬长避短,总结我想要的最佳东西.
PHP
语言核心
CPAN被称为"Perl的标准库".这并没有对Perl的标准库做过多说明,但它蕴含了健壮的核心可以构建强大的东西的思想.
基本原则
PHP最初很明确的是为非程序员设计的(言外之意,非专业程序);根源已经很难脱离.从PHP2.0文档中挑选出来的对话:
一旦你开始为每个类型区分不同的操作符,你就开始使用语言变得复杂了.例如,你不能为strings使用==,你现在必须用eq.我没看出这点来,特别是那些类似PHP的脚本语言,它们大多数相当简单而多数情况下,作为非程序员,只想要一门包含少量基本逻辑语法的语言,而不想付出过多学习曲线.
>>PHP为保持前进不惜代价.什么都有比没有好.
javascript教程推荐>>这不是个正确的设计原则.早期的PHP受Perl影响;大量的标准库参考C使用"out"参数;OO部分的设计像C++和Java.
>>PHP从其它语言中引入大量的灵感,但对那些熟知其它语言的人,仍然难以理解.(int)看起来像C,但是int并不存在.命名空间使用\.新的数组语法使用[key=>value],不同于任何其它语言定义hash字面量的形式.
>>弱类型(例如,默默的自动在strings/mumbers/等间转换)是如此的复杂.
>>少量的新特性以新语法实现;大多数工作通过函数或者看起来像函数的东西完成.除了类的支持,这理所当然的需要新的操作符和关键字.
>>本页列出的问题都有解决方案--如果你想资助Zend修复它们的开源编程语言的话.
>>漫漫,其修远.思考下面的代码,从PHP文档的某地方挑出来的.
这段代码將做什么?如果array_diff將参数以hashes看待,它们明显是不同的;相同的keys有不同的值.如果以list看待,它们仍然是不同的;值的顺序不同.
事实上array_diff认为它们相等,因为它以sets对待:仅仅比较值,忽略顺序.
>>同样,array_rand随机选择keys时,也有奇怪的行为,这对大多数需要从列表中挑出东西的用例没什么帮助.
尽管大量PHP代码依赖key的顺序:
>>如果两个数组混合的话,会发生什么?我留给读者自己弄清楚.(我不知道)
>>array_fill不能创建0长度的数组;相反它会发出并返回lse.
>>所有的(很多的...)排序函数就地操作而什么都不返回.想新建一个已排序数组的拷贝,没门;你不得不自己拷贝数组,然后排序,然后再使用数组.
>>但array_reverse返回一个新数组.
>>一堆被排序的东西和一些键值对听起来像是个某种强大的处理函数参数的方式,但,波西米亚风格没门.
非数组
>>标准库包含"快速哈希","特定的强类型"的hash结构OO实现.然,深入它,有4类,每种处理不同的键值对类型组合.不清楚为什么内建的数组实现不能优化这些极其普通情况,也不清楚它相对的性能怎样.
>>有个ArrayObject类(实现了4个不同的接口),它包装数组让它看起来像对象.自定义类可以实现同样的接口.但只有限的几个方法,其中有一半不像内建的数组函数,而内建的数组函数不知道怎样对ArrayObject或其它的类数组的类型操作.
函数
>>函数不是数据.闭包实际上是对象,但普通的函数不是.你甚至不能通过它们裸名称引用它们;var_dump(strstr)会发出并猜测你的意思是字符串字面量,"strstr".想辨别出字符串还是"函数"引用,没门.
>>create_function基本上是个eval的包装者.它用普通的名字创建函数并在全局范围安装它(因此永远不会被垃圾回收---不要在循环中使用!).它实际上对当前上下文一无所知,因为它不是闭包.名字包含一个NUL字节,因此永远不会与普通函数冲突(因为如果在文件的任何地方有NUL的话,PHP的解析器会失败).
>>Declaringafunctionnamed__lambda_funcwillbreakcreate_function—theactualimplementationistoeval-createthefunctionnamed__lambda_func,theninternallyrenameittothebrokenname.If__lambda_funcalreadyexists,thefirstpartwillthrowatalerror.
其它
>>对NULL使用(++)生成1.对NULL用(--)生成NULL.
>>没有生成器.
Web框架
执行
>>一个单一共享文件php.ini,控制了PHP的大部分功能并织入了复杂的针对覆盖什么与何时覆盖的规则.PHP软件能部署在任意的机器上,因此必须覆盖一些设置使正常,这在很大程序上会像php.ini这样的机制的使用.
>>PHP基本上以CGI运行.每次页面被点击,PHP在执行前,重编译整个.就连Python的玩具框架的开发都不会这样.
>>这就导致了整个"PHP加速器"市场的形成,仅仅编译一次,就能加速PHP,就像其它的语言一样.Zend,PHP的幕后公司,將这个做为它们的商业模式.
>>很长时间以来,PHP的错误默认输出给客户端--我猜是为开发提供帮助.我不认为这是,但我仍然看到偶尔会有mysql错误出现在页面的顶部.
>>在<?php...?>标签外的空白,甚至在库中,PHP以文本对待并解析给响应(或者导致"headersalreadysent"错误).一个流行的做法是忽略?>关闭标签.
部署
部署方式常常被引述为PHP的最高级部分:直接部署文件就可以了.是的,这比需要启动整个进程的Python或Rury或Perl要容易.但PHP留下了许多待改进的地方.
我很乐意以应用服务器的方式运行Web应用程序并反向代理它们.这样的代价最小,而好处多多:你可以单独管理服务器和应用程序,你可以按机器的多或少运行运行多个或少量应用进程,而不需要多个web服务器,你可以用不同的用户运行应用,你可以选择web服务器,你可以拆下应用而无需惊动web服务器,你可以无缝部署应用等等.將应用与web服务器直接焊接是的,没有什么好的理由支持你这么做.
>>每个PHP应用程序都使用php.ini.但只有一个php.ini文件,它是全局的;如果你在一个共享的服务器上,需要修改它,或者如果你运行两个应用需要不同的设置,你就不走运了;你不得不向组织申请所有必须的设置并放在应用程序,如使用ini_set或在Apache的配置文件或在.htaccess设置.如果你能做的话.可能wow,你有大量的地方需要检查以找出怎样获取已设置的值.
>>类似的,"隔离"PHP应用的方法也不容易,它依赖于系统的其它部分.想运行两个应用程序,想要不同的库版本,或不同的PHP版本本身?开始构建另一人Apache的拷贝吧.
>>"一堆文件"方案,除了使由像只病重的笨驴外,还意味着你不得不小心处理白名单或,以控制什么东西可访问,这是因为你的URL层次也就是你的代码树的层次.配置文件和其它的"局部模块"需要C之类的东西守护以避免直接加载.版本控制系统的文件(如.svn)需要.使用mod_php,使得文件系统的所有东西都是潜在的入口;使用应用服务器,仅有一个入口,并且仅通过URL控制调用与否.
>>你不能无缝的升级那堆以CGI-style运行的文件,除非你想要应用崩溃和出现未定义行为,当用户在升级的间歇期点击你的站点时.
>>尽管配置Apache运行PHP很"简单",仍然会有一些陷阱.而PHP文档使用SetHandler使得.php文件以PHP方式运行,AddHandler看起来运行良好,然而事实上会有问题.
当你使用AddHandler,你在告知Apache"以php执行它",这是一个可能的处理.php文件的方式.但!Apache对文件的扩展名不这样认为.它被设计为能支持如,index.html.en这样的文件.对于Apache,文件可以同时具有任意数量的扩展名.
猜想,你有个文件上传的表单,存储一些文件到公共目录中.确保没人能上传PHP文件,你仅仅检查文件不能有.php扩展名.所有的需要做的只是上传以foo.php.txt命名的文件;你的上传工具不会看出问题,Apache会认为它是个PHP,它会很高兴的执行.
这里不是"使用原始文件名"或"没有更好的验证"导致的问题;问题是你的web服务器要被配置用来运行任何旧代码,使得PHP"容易部署".这不是理论上的问题;我已发现很多实际的站点有类似的问题了.
缺失的特性
我认为所有这些都是以构建一个Web应用为中心的.对PHP看起来很合理,是它的销售卖点之一,它是"Web语言",理应有它们.
>>无模块系统.PHP就是模版.
>>无XSS过滤器.htmlspecialchars不是XSS过滤器.
>>无CSRF.你必须自己做.
>>无通用标准的数据库API.像PDO这类东西不得不包装每个特定数据库的API,分别抽象不同部分.
>>无由系统.你的站点结构就是你的文件系统结构.
>>无认证或授权.
>>无开发服务器.
>>无交互调试模式.
>>无一致的部署机制;仅仅"拷贝所有文件到服务器中".
安全
语言边界
PHP的蹩脚安全机制可能会放大,因为它利用某语言拿出数据,又把它转存到另一个中.这是个坏注意."<script>"可能在SQL中意味着什么都不是,但在HTML中就很是了.
让情况更糟糕的是通常有人哇哇喊到"你的输入要消毒".那完全错误;你不可能有什么魔法使块数据完全"干静".你需要做的就是对语言说:SQL使用占位符,进程孵化使用参数列表,等等.
>>PHP公然鼓励"消毒":有个数据过滤扩展可以做到.
>>所有的addslashes,scripslashes,和其它的slashes相关的东西都是废物,毫无用处.
>>我只能告诉你这么多,无法安全的孵化进程.你仅能通过shell执行字符串.你的选择是疯狂的转义,并希望默认的shell使用正确的转义,或手动的pcntl_fork_exec和pcntl_exec.
>>所有的转义命令和转义参数存在大致相同的描述.注意在Windows中,转义参数不工作(因为它假设成Bourneshell语议),转义命令仅仅用空格替换一堆标点符号,因为没人能搞清楚Windows命令转义行为(它可能默默的你试图做的任何事情).
>>原始的内建MySQL绑定,仍然广泛使用,它无法创建preparedstatements.
直到今天,PHP文档关于SQL注入的还是让人抓狂的做如类型检查,使用sprintf和is_numeric,在每个地方手动的使用mysql_real_escape_string,或在每处手动使用addslashes(这个"可能更有用"!)这样的实践.并没有提到PDO或参数化,除了在用户评论中有点线索.至少在两年以前,我就有具体的向PHPdev抱怨过了,他被惊动了,而页面却从未变过.
Insecure-by-deult
>>register_globals.它被默认关闭的,而在5.4中去除了.我不在乎.
>>include接受HTTLURLS.和一样.
>>Magicquotes.Soclosetosecure-by-deult,andyetsorfromunderstandingtheconceptatall.
核心
PHP解释器本身就有一些恼人的安全问题.
>>2007年的时候,解析器有个整数溢出漏洞.修复始于if(size>INT_MAX)returnNULL;从那以后就走下坡了.(对于那些不需要使用C的人:曾经,INT_MAX是适合变量最大整数.我希望你能从这里搞清楚其余的东西.)
>>最近,PHP5.3.7包括了个crypt()函数,有个漏洞让任何人可以用任何密码登录.
>>PHP5.4是容易遭受服务,因为它需要Content-Length头(任何人都可以设置),并试图分配更多内存。这是一个坏主意。
我可以挖掘更多,但重点不是这有很多X漏洞--是软件就有bugs,无论如何都有.这些自然是令人咋舌.我并没有特意寻找这些;但在过去的几个月里,它们自己送上门来了.
总结
一些评论会理所当然的指出我没得出任何结论.好吧,我是没有结论.如果你一看到了这里,我假设一开始你就同意我了:)
如果你仅了解PHP而对学习其它东西感兴趣,可以看看Python教程,尝试Flask这个为web准备的家伙.(我不是它的模版语言的铁杆粉丝,但它确实很好的完成了这些工作.)它將你的应用分成多个部分,但它们看起来仍然是一致的.我可能稍后会写个关于这个的贴子;旋风般的介绍整个语言和不同于这里所说的web堆栈.
之后或对于更大的项目,你可能需要Pyramid,一个中等规模的框架,或者是Django,一个构建站点的复杂的框架,如Django站点.
英文:
原文链接:
【编辑推荐】

























浙公网安备 33010602011771号