写了这么久PHP,在心血来潮在StackOverflow上回答了别人PHP的问题,没想到被扣分还说没常识,求研判。

2013-04-29 12:40:51 +08:00
 raincious
这是我回答的地址:
http://stackoverflow.com/questions/16262944/emailing-an-array-from-html-form-via-php/16263381#16263381

之前总是通过Google得到StackOverflow的搜索结果,于是昨天就注册了,正好遇到别人提的问题我知道,于是就回答了,但是。。。。但是啊。。。就是在补充一点意见的时候,某个家伙。。就这么给我的回答扣分了。。。。感觉很悲剧。

但是还是想知道我这样处理是不是正确,所以发上来希望大家讨论下。

具体是这样的,我认为在PHP里,在楼主那情形下不需要isset,关掉E_NOTICE的警告就好了。但那家伙认为,我这样做违背了常识,(意思似乎说error_reporting(E_ALL)万岁?),但是我觉得不对。

所以想问问大家具体都是怎么处理变量未初始化的?

我先来说说我,一般都是习惯于先初始化好,不可能存在不初始化的变量,也就不需要isset了:

function($input) {
$sA = $sB = '';
$iA = $iB = 0;
$aA = $aB = array();

// do your code here
}

大家呢?
10838 次点击
所在节点    PHP
48 条回复
chenz
2013-04-29 15:54:32 +08:00
你不是没看到大家的观点,而是你根本选择性地失明

我再说一次我的观点,以及你选择性忽略的一些点

1. 我开E_ALL,是为了能彻底去掉所有notice以及其他错误。也就是说,我的代码的最终版本,正常情况下,是不会抛出notice或者warning或者更高级别的错误的。
2. 错误是不会飘在页面上的。开发环境下,我最多看到一次notice或者warning,一看到我就解决掉。而在生产环境,就算我不解决掉这些notice和warning,也是永远不会有任何错误显示给用户的
3. 你不能根据一个例子没有问题,就假定所有情况下都没有问题。所以单单根据你那个request来讨论是否应该开启notice或者是否该使用isset是没有任何意义的。为什么要开启notice,我之前已经说得很清楚了,你不能保证所有人,以及所有场景下,都能严格初始化变量
4. clearstatcache的问题请你回应,你不理解这个,你的测试代码就没有任何意义。当然,就算你了解了这个,你的代码依然没什么意义。但是至少往有意义的方向迈进了一步
5. ?>的问题跟本帖话题无关,但是我也希望你能阅读一下psr。而且既然你这么关注你的response http header,你就必须知道这个?>问题也是和它息息相关的
6. 你当然可以设置自己的error handler,但是处理notice或者warning这样的error没有任何意义。所有的notice和warning都应该写代码解决掉,而不是让程序处理这些错误。或许唯一的意义就是你可以写一个让自己能更快地发现这些错误的handler,然后解决掉这些notice/warning


上面几点,除了最后一点,我在之前的回复里已经提到过了。你为什么会没看到"各位的观点"呢?
raincious
2013-04-29 16:27:33 +08:00
亲爱的@Js,我没有关掉警告,只是让他不显示。因为在我看来貌似多次@不如关掉,因为貌似@每一次都有消耗,屏蔽只消耗一次。然后自己做个处理,速度就快了。这些错误你之后都可以手动读出来的。

./test/1.txt - ./test/10000.txt大小都是3K左右的文件,内容相同,文件名超出部分NOT FOUND。

我来问这个问题,主要是具体的想知道大家怎么处理error_reporting。我早先写框架的时候遇到了很多很多问题,才导致我使用了这种处理方式。

所以我想知道,各位就算开了error_reporting让他直接显示,然后怎么办?遇到一条就检查初始化或者屏蔽么?我之前得到另一个做开源的开发者的一些建议(只是人家现在在做硬件之类的),说“PHP不是静态语言,(非关键情况下)不需要特意屏蔽某些错误”。当然,他是在看到我ftp那些操作的时候给我的建议。

@chenz,我还是没看到你的观点。你帖子的内容我当然都看过了。我想知道的是你遇到这种错误,具体怎么做的?我觉得你没有发挥程序员的长处:分析目的;解决问题。

那我就猜猜,你看对不对:你一般情况下都是开E_ALL,然后当出现error你就去debug掉是吧?

此外呢,其实我们的代码都不会抛出E_N、E_W,不同的是,你用PHP自己的方式处理了,配合Xdebug之类可能更好用。我用自己handler处理了,这样甚至可以直接显示给用户,但是调试麻烦。这就是我们处理方式的区别。

不知道我猜的对不对。

此外,其实就clearstatcache的问题。。。其实。。我的realpath_cache_size,是关闭的。甚至与MySQL的Connection timeout都只有1秒。我比较习惯于严苛的运行环境,这样部署的时候会比较爽。

那么焦点就是这个了:关闭E_NOTICE显示,好还是不好。(注意,不是忽略所有NOTICE错误)

另外我同意的一点是,不应该就楼主的问题来判断E_NOTICE是不是应该屏蔽显示,楼主只是变量未初始化。但是诸如unserialize失败也会有E_NOTICE。

就unserialize的例子来说吧,我一般会用

if ($a = unserialize($str))

自行判断上面的操作有没有问题,这样的情况下,一个E_NOTICE是不是就多余了呢?而且很多情况下,你不能保证给unserialize的字符串就是他想要的啊。
python
2013-04-29 17:15:21 +08:00
@chenz 赞同+1

@raincious

对于变量在使用前是否先isset,还是先初始化,
==============
我的做法:
$option = array(
//如果是用户的输入,先isset
'file_name' => isset($_POST['file_name']) ? $_POST['file_name'] : '',
//5.2.0以上可以用$fileName = filter_input(INPUT_GET, 'file_name');
);
dododo($options);

function dododo(array $options)
{
!isset($options['file_name']) and die('need a file..');
//如果不是用户的输入,就在使用新变量前先初始化好,如$file_content;
$file_content = '';
is_file($options['file_name']) and is_readable($options['file_name']) and $file_content = file_get_contents($options['file_name']);
return $file_content;

}

一般都是习惯于先初始化好,不可能存在不初始化的变量,也就不需要isset了
================================
对于这个,我觉得,在处理用户的输入时,默认值应该是为了照顾大众的习惯而设置的,不应该程序就帮用户输入了.用户的输入总是不可靠的,当然要isset了..直接$_REQUEST['visitor'] === 'yes' ,关闭了E_NOTICE, 会导致你看不到unserialize的出错时产生的E_NOTICE...

对于 error_reporting, 生产环境用0,然后写日志, 用户访问出错时显示空白或者错误提示"您访问的页面有点问题"之类的内容, 不会让错误乱飘的..开发环境用E_ALL(5.4以下用E_ALL | E_STRICT)..关于性能,@屏蔽影响往往不是重点...
maomaosang
2013-04-29 18:19:59 +08:00
1.楼主你知道ini_set里面有个东西叫做display_errors么,生产环境把这个关掉,所有的报错在error.log里面全都能看到,不会飘在页面上……

2.咱们真的是E_ALL开发的,因为原则是:开发环境解决所有报错,即使是notice;生产环境关掉display_errors,用户啥报错都不会看到,如果有报错,全在log里。这是原则,雷打不动,notice都不准有。

3.我没太明白你set error handler的用意,你set一个handler,然后这个handler对所有的error处理?怎么处理?写日志?日志本身自带就有啊。难道你还写一个函数专门handle这些error?有这个时间你干嘛不写代码把error解决了。。
raincious
2013-04-29 19:47:19 +08:00
@maomaosang

display_errors我当然也有做。
https://code.google.com/p/faculaframework/source/browse/trunk/include/class.oops.php#60

那么,为什么我要关掉error_reporting,其中一个原因就是,你的脚本在服务器中运行。可能你自己调试本地日志没问题,但服务器上谁也不知道。

首先,如果一个服务器上跑上百个网站,那么日志会变得很难整理,每天产生1GB的日志,我觉得没人愿意去处理。而且我这人对I/O是有洁癖的,越少越好,何况如果服务器是SSD的盘。

所以,我给一个set error handler,就能够自己筛选错误级别,程序遇到之后就会提交到调试服务器上,调试服务器自动给你整理好,方便你知道,甚至给你发个手机短信邮件什么的告诉你得回公司加个小班(还能跟绩效什么的关联起来,多好阿)。同时,这样可以避免更多人能接触到生产服务器。

可能又有人说了,写个小程序周期整理下error.log不就行了么?我觉得各有做法,我用这手比较顺而已。

当然,我觉得大家避免E_NOTICE,最主要的是避免Bad style($a[name]这样的),这一点我也有洁癖,根本不会犯这错(是的,对我来说这就是错),所以我不需要解析器帮我解决。但是至于消灭E_NOTICE,我觉得有点过了,有一刀切的意味。

关键还是在于你要知道自己在做什么,PHP会怎么反应,这反应会有什么后果。

至于isset要不要,我也有看法,我的意见是:

如果这变量经常未被设定,那么isset可以节省一点时间;
如果这个变量经常被设定,那么不使用isset会使用更多时间;

但是由于在任何情况下,节省或浪费的时间我测试50000次只相差0.05秒,还没一次页面数据库使用的时间多,所以用isset和不用,在类似对 用户是否输入 和 输入是否是真 的判断没区别的情况下,也就是习惯问题了。

我不知道我这样说@chenz是否同意。
chenz
2013-04-29 19:54:57 +08:00
1. clearstatcache跟realpath_cache_size没有任何关系。前者是清空文件系统信息的缓存(例如filemtime),后者是文件路径的realpath的缓存

2. 你说 "我之前得到另一个做开源的开发者的一些建议(只是人家现在在做硬件之类的)”。我的意见是,你叫这个"开源的开发者"好好地做硬件吧。PHP水很深,不是专业的PHP开发人员不要乱评论。

3. > 那我就猜猜,你看对不对:你一般情况下都是开E_ALL,然后当出现error你就去debug掉是吧?

你真的不用猜,我上面已经说过很多次了。我,也可能包括很多这里回复者,对notice错误是零容忍

4. 我猜你依然不知道为什么?>是个问题吧?因为你直到现在对这个都没有回应
raincious
2013-04-29 20:26:02 +08:00
@chenz,建议你语气和蔼点,像我,呵呵。

1,是的因为我需要这些缓存,所以我从来不清除他们。当然也就没有自己尝试过clearstatcache。我觉得他们应该像用C++时那样,大多数情况下按提供使用。由于我对IO能省则省,所以从来没有需要手动clearstatcache的情况。这确实是一个知识缺失。

2,30年+的开发经验,C + C++ + PHP等,现在在做龙芯,元老级人物。我把他搬出来,确实是因为他说过。当然他也给了我很多不太好的建议。我正在逐步发现这些问题,包括这个帖子。当然他的很多建议我也是很受用的。

3,不设条件0容忍?我不是做不到,只是觉得一刀切方式不好,可能是管理成本问题。当然我的固然观点是,要是某人觉得你说话他不喜欢,是不是让大家都不许说?当然,让程序运行的更完美是所有程序员的目标的确。

4,?>,我觉得我的解决方案更好,于是我还是坚持自己的,这倒不是不理解,有人说?>不要更安全(为什么呢?),有人说?>不要可以避免白空间问题。但是,我没有白空间问题啊。
chenz
2013-04-29 21:17:05 +08:00
1. 你之前当然可以不知道clearstatcache,每个人都有不知道的点。但是在我给你clearstatcache的链接的情况下,你居然能扯到realpath这个东西。所以我质疑你的态度或者能力

2. 30年+经验,见识了,1983开始写程序?敢问是哪位?陈老?

3. 对notice零容忍有什么成本的?我接触的绝大多数(如果不是全部)PHP程序员和团队都是对notice零容忍。而且从来没人觉得有什么问题。你举例"你说话他不喜欢"的例子真可笑

4. 什么叫你的方案更好?你所谓的更好,是完全错误的做法。除非你每次都用hexdump检查你的PHP文件并确保最后两个字符是3f 3e,否则肯定无法确保?>是最终的两个字符。这个不但是psr规定这样,php手册也写明了这一点:http://php.net/manual/en/language.basic-syntax.phptags.php If a file is pure PHP code, it is preferable to omit the PHP closing tag at the end of the file. 在非view文件里写?>的PHP程序员,不是个合格的程序员
chenz
2013-04-29 21:23:07 +08:00
另外,对于4. "这倒不是不理解"。你完全没理解,如果你理解,就不会说"有人说"。

"有人说","某某前辈说",在我看来,就是bullshit,完全不靠谱的来源。如果你注意到,我上面所贴的几个链接,都是权威的来源,而不是"有人说"。引用权威来源,这才是学术讨论所采用的正确的来源引用方式
ShiningRay
2013-04-29 22:20:36 +08:00
既然你这么认为就这么认为好了,自己写套nb的开源软件出来证明自己就行了,这个世界就是这样的
ljbha007
2013-04-29 22:33:51 +08:00
凡事先使用isset判断是个好习惯
有警告说明代码有问题 应该改代码 而不是把警告关掉 这是个非常坏的习惯
所以楼主叫人家改掉好习惯并且叫人家养成坏习惯当然必须down vote啊

我也down了一个
maomaosang
2013-04-29 22:34:43 +08:00
“可能你自己调试本地日志没问题,但服务器上谁也不知道。”我为什么不知道?error.log全都知道啊,这句逻辑挺混乱的我没太看懂。

"如果一个服务器上跑上百个网站,那么日志会变得很难整理,每天产生1GB的日志,我觉得没人愿意去处理。而且我这人对I/O是有洁癖的,越少越好,何况如果服务器是SSD的盘。" 如果你在本地开发时对notice零容忍,我相信线上的error.log是不可能达到1G的。

"就能够自己筛选错误级别,程序遇到之后就会提交到调试服务器上,调试服务器自动给你整理好" 你这个整理程序真的足够智能?如果你有空维护这个整理程序,为什么不愿意消灭掉notice呢。我不知道你这个整理程序是怎么个逻辑,如果对于isset的notice直接扔掉,那么导致的问题可能会很严重。因为你要知道有时候一个notice背后反映的很可能是一个feeeeetal error,只是在那个页面上没表现出来罢了。

至于小程序整理error.log,您真的有必要这么矫情么。。我们都是肉眼整理error.log的,因为里面的内容实在是少之又少。。这就是notice一刀切的好处。

其实我们这里纠结的不是用不用isset,isset执行效率是否高效,而是处理notice的态度。我不怀疑你在某些方面的技术能力,你在SO里面也的确解决了楼主的问题(其实就是个disabled嘛),但是error reporting这些细枝末节的东西,业界都总结了best practice,这些practice在我写PHP的过程中,一路使用下来,是能的的确确感受到其"best"之处。包括@chenz 说的?>问题,可能你代码习惯好,写一年代码都不会在?>后面加异常字符,但是你如果一年零一天的时候加了,你遇到这个问题,可能就调试一下午,到时候你就哭了。。平常你是没有白空间,但是万一光标在那儿,键盘无意碰了一下呢?

另外我很奇怪你用SSD的方式,完全可以挂两个盘,一个SSD一个机械HD,你log放在机械HD里面就行了嘛。。。
rqrq
2013-04-29 23:07:43 +08:00
我认为程序员必须遵守墨菲定律,lz觉得如何?
多少年的开发经验不能证明任何问题。译言网有篇讲逻辑的文章,推荐lz阅读。
dorentus
2013-04-29 23:49:43 +08:00
SO 上给答案减分的话是扣分人和被扣分人各减一分的
你这个 0+ 5- 的结果本身已经可以说明问题了
allenhsu
2013-04-30 00:05:59 +08:00
@chenz @python
我是 PHP 小白,关于这个 isset 的问题,想请教一下:如果先设置一个 defaultOptions 的 array,然后 array_merge(defaultOptions, $_GET),后面就不检查 isset 直接使用,这种方法是否合理?对效率的影响大不大?
raincious
2013-04-30 00:32:53 +08:00
@chenz 我的方案更好是比你的方案好。因为你的方案根本无法解决header的问题,仍然不可避免ERR_CONTENT_DECODING_FAILED,而我目前的方案是header队列,虽然无法保证别人不在?>后面写东西,但是我可以保证,于是我就这么写,这叫代码洁癖。别人调用自然可以用他们的方式。

我没有质疑各位的Optimalled performance。既然是为了让程序运行更好,于是我只是禁止了error_reporting,不做本地记录,但是所有的错误都更友好的被获取了。

还有,关于你那个bullshit。。。你那个10年的怎么回事?另外,我来这里询问,是想得到准确答复。为何以及如何对待E_NOTICE。这就是为什么在python给我回复之后我答谢了他。我相信这里的人应该比我更有经验处理这些问题,这跟我经常请教我那位朋友是一个心理——因为你们处理的情况多,所以我能得到更有效的答复,否则我为什么不去CSDN?

请注意,你们答复的结果对我未来说也是“听某人说”,希望这不是bullshit。

@maomaosang 如果这世界上的程序都是我写的,那我真的会保证不会有那么多INFO、WARNING、ERROR。但是这就是世界。你有程序报的错要记录,除了程序,用户输入有问题要记录、用户页面刷新太多要记录、登录操作要记录、管理操作要记录、给用户什么广告了要记录等等等等。记录个错误只是小意思,顺便而已。否则会用专门的服务器来做这个?

此外我认为,程序服务器不应该用来存储除了程序之外的东西。用户上传FTP走,缓存memcache,数据mysql,日志远程。当然,事实上我也不能保证这一点。

@rqrq 当然,但我不认为即使你抑制了E_NOTICE,就能解决全部问题不是么?我的扩展观点是,大家除了E_NOTICE,更应该关心自己的代码质量,而不是完全Test Driven。
raincious
2013-04-30 00:38:13 +08:00
@allenhsu

如果array_merge中有一个参数不是数组,则会返回E_WARNING,这是没有任何办法的,所以必须

if (is_array($defaultOptions) && is_array($_GET)) {
$newArray = $defaultOptions + $_GET // "有人说"更快
}
lfeng
2013-04-30 01:26:43 +08:00
@dorentus 嗯,我也觉得这个0+ 5- 的结果本身已经可以说明问题了。

另外看到这个帖子的是我想到的第一个词是掩耳盗铃,当然我誓死捍卫LZ坚持自己观点的权利,其实这个问题根本就没有什么好挣的,自己觉得怎么爽就怎么用呗,反正到最后被坑的是自己,只要你不做后面接手的那个倒霉蛋就成了。
yakczh
2013-04-30 08:25:17 +08:00
stackoverflow的质量高,这是这样一步步炼成的
Leask
2013-04-30 09:29:12 +08:00
现在才看到这个帖子,亏了。
如果早看到,我会用 @chenz 完全一样的观点回复一下楼主。

说实话,这都是十分十分基础的常识。

不谈技术,我希望楼主能消化一下大家的观点,找相关文档看看,留意一下优秀的实现是如何处理的。在充分调研后再给自己一个定论也不迟。

尊重事实,客观、虚心、耐心,我觉得是一名程序员的基本素养。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/67309

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX