V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
raincious
V2EX  ›  PHP

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

  •  
  •   raincious · 2013-04-29 12:40:51 +08:00 · 10777 次点击
    这是一个创建于 4259 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这是我回答的地址:
    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
    }

    大家呢?
    第 1 条附言  ·  2013-04-29 15:36:49 +08:00
    我当前的观点:

    你应当error_reporting(E_ALL ^ E_NOTICE甚至0); 然后你必须set_error_handler();

    举那些例子就是为了自证处理E_NOTICE会有额外消耗,把话题扯太远是没有意义的。
    第 2 条附言  ·  2013-04-30 00:44:29 +08:00
    失望啊,貌似很多人都在说:你怎么能无视E_NOTICE呢无视E_NOTICE呢无视E_NOTICE呢。我什么时候建议无视E_NOTICE了?

    我只是在LZ问题下讨论isset是否需要。

    而且我对E_NOTICE的观点是不是你应当屏蔽,而是当你遇到有问题的E_NOTICE应当处理。当处理E_NOTICE影响性能且不会导致问题时,应当压制。仅此而以。

    而error_reporting这项设置就算你设为E_ALL,不对有错误的问题进行压制,也还是有问题。

    顺便说一句,set_error_headler一直能相当于E_ALL一样的安静的获取错误,即使error_reporting(0)

    哎,希望你们真能理解。另外感谢@chenz的?>提示,以后可能会用到的。
    第 3 条附言  ·  2015-02-23 14:23:42 +08:00
    现在再来看这个答案:

    乃们说的都是对的呢。适当使用isset确实有助于提高程序质量,而且没有了NOTICE,可以更加细致的输出调试信息,非常有助于找出BUG。

    以上。
    48 条回复    1970-01-01 08:00:00 +08:00
    python
        1
    python  
       2013-04-29 12:57:29 +08:00
    用E_ALL,写好了,各个环境都能通过...

    对于用户的输入,要用isset处理, 程序不应该改变用户的原输入,即使是恶性的.
    AlloVince
        2
    AlloVince  
       2013-04-29 13:04:38 +08:00
    关掉E_NOTICE不是一个好习惯,正是因为写法中可能存在隐患,所以才会有NOTICE报出,php稍微注意一下完全可以写出通过E_ALL的代码。这样对项目对自己都有好处。

    变量未初始化的问题

    如果在功能函数中,提前声明变量设默认值即可。

    如果在模板引擎以及一些处理大批量参数的场景,最好用OOP处理,活用__set(),__get(),__isset()即可
    raincious
        3
    raincious  
    OP
       2013-04-29 13:15:44 +08:00
    LS们真的用E_ALL?

    我一开始学PHP的时候也是用E_ALL,一个页面打开,上百个isset调用,主要在数组处理上。

    我实在没办法理解为什么程序员要将安全处理什么的交给解析器。

    另外,isset跟安全处理没什么直接关系。他不能帮你判断用户输入是不是你想要的。一般人也主要用来防止Global Variable污染。

    但是防止Global Variable污染你可以在函数或者什么地方声明啊,没事调用isset做什么呢?

    另外,根据你们的说法,如果类似我这样保证变量使用之前都提前声明的话,就不需要开E_NOTICE了吧?

    此外,我确实不相信有人的程序是error_reporting(E_ALL),你们的开发组真的是这样开发程序的么?那么你们其他意外怎么处理,比如file_get_content一个不存在的文件,这可是E_WARNING啊,如果不屏蔽,报错给用户不说,你们的HTTP Header不是会很糟。

    如果为了file_get_content不报错,得file_existe吧?还得is_file吧?那么就3个IO操作了,值得么?

    感觉E_ALL只是对新学PHP的人的一种手段而已。
    chenz
        4
    chenz  
       2013-04-29 13:21:05 +08:00
    1. 不应该关掉notice警告。如果你关掉notice,那么当一个需要set的变量没有set的时候,你可能无法察觉。但是所有的警告都应该写入log,而不是打印出来(至少生产环境)
    2. 你应该用isset检查。不一定是在Yes那一行,可能是在更之前做这个isset检查。但是无论什么情况都应该做这个检查


    你虽然习惯初始化,但是你不能保证你每次都记得初始化,你也不能保证团队里每个人都记得初始化



    话说,我怎么感觉我回到了10年前的那些PHP论坛和邮件组?当年我们就是在频繁讨论这些话题。虽然这10年来PHP技术有长足的发展(匿名函数、composer、psr等),但是isset该如何使用,notice是否应该关掉,我想不会有太多变化吧
    chenz
        5
    chenz  
       2013-04-29 13:28:15 +08:00   ❤️ 1
    >> 此外,我确实不相信有人的程序是error_reporting(E_ALL),你们的开发组真的是这样开发程序的么?那么你们其他意外怎么处理,比如file_get_content一个不存在的文件,这可是E_WARNING啊,如果不屏蔽,报错给用户不说,你们的HTTP Header不是会很糟。

    我的所有代码都是在E_ALL下写的,有notice我会马上修正。

    file_get_content的问题,当然是if (file_exists($f) && file_readable..)才file_get_contents。

    另外,就算没有做上面的判断,也不会把错误报告给用户。因为生产环境下当然会把所有warning写入服务器的log file,而不是打印出来。用户永远看不到这些错误报告。如果你们团队没有这样做,我可以说你们的团队真的还需要很多磨练
    skey
        6
    skey  
       2013-04-29 13:42:26 +08:00
    error_reporting(E_ALL) +1
    Js
        7
    Js  
       2013-04-29 13:45:39 +08:00
    @raincious 针对性能方面质疑的前提就错了, php屏蔽错误(包括error_reporting和@)是需要额外开销的, isset($var) && $var==='xxx' 性能比 $var==='xxxx'高多了, 同理对于一个无法确定是否存在的文件, is_readable($filename) && include($filename) 也比 @include($filename)高多了. 不信的话可以做下benchmark。 关闭日志是为了在生产环境更安全一点(万一一个不可控的情况爆了些密码出来怎么办?), 平时开发应该把警告当错误看的
    raincious
        8
    raincious  
    OP
       2013-04-29 14:04:43 +08:00
    我觉得各位还是没有考虑好这个问题,或者最好能举个例子说明楼主那个==YES的if如果再没初始化的时候会有什么危害。

    当变量未初始化
    return $_REQUEST['visitor'] == 'Yes' ? true : false; // False

    当变量初始化并等于其他值
    return $_REQUEST['visitor'] == 'Yes' ? true : false; // False

    当变量初始化并等于Yes
    return $_REQUEST['visitor'] == 'Yes' ? true : false; // True

    当变量未初始化并等于Yes // 未初始化如何等于?
    /* */


    可见情况是一致的。

    另外,就算是为了防止全局变量污染:
    http://www.php.net/manual/en/ini.core.php#ini.register-globals

    PHP 5.4.0之后就没有自动全局变量注册了。于是乎,抱歉,使用这条利用来进行isset已经不靠谱了。

    好吧,我整理下我的观点,基本不变:就变量是否初始化来打开E_NOTICE会增加不当开销,建议调试时打开,开发时写入次要日志,生产时关闭且不输出。

    当然E_NOTICE还有其他错误,但在我看来,这跟程序员水平有关。如果为了安全,不应该让程序员来承担不必要isset的义务,而应该在核心上避免isset的需要(当然,不是完全禁止isset)。如果你们不明白,可以参看我3年前写的代码:

    https://code.google.com/p/faculaframework/source/browse/trunk/include/inc.initializer.php#66

    @Js 此外根据性能问题,我特别进行了测试,观点仍然是我不做变更,这是结果:

    操作次数都是5000次

    T1: 判断下文件
    T2: file_get_content这个文件
    T3: file_exist && is_readable && file_get_content 这个文件

    Array
    (
    [Test1] => Array
    (
    [LastStartTime] => 1367215477.7918
    [LastEndTime] => 1367215477.7918
    [LastUsedTime] => 3.6001205444336E-5
    [AvaTime] => 3.5916407863653E-5
    [Total] => 0.33174586296082
    )

    [Test2] => Array
    (
    [LastStartTime] => 1367215478.5506
    [LastEndTime] => 1367215478.5507
    [LastUsedTime] => 0.00010204315185547
    [AvaTime] => 0.00010305986018425
    [Total] => 0.64278268814087
    )

    [Test3] => Array
    (
    [LastStartTime] => 1367215479.5682
    [LastEndTime] => 1367215479.5684
    [LastUsedTime] => 0.00016403198242188
    [AvaTime] => 0.00016249667572205
    [Total] => 0.90015578269958
    )

    )

    请不要参考AvaTime,这是线性平均时间,不准确

    这是测试代码:
    http://pastebin.com/i0ajTvMf


    Bites Me!
    AlloVince
        9
    AlloVince  
       2013-04-29 14:23:05 +08:00
    @raincious 我还真的就是E_ALL

    https://github.com/AlloVince/eva-engine/blob/master/init_autoloader.php

    isset用的特别多,代表你项目的OOP程度不深或者代码组织不够好,还主要依赖函数式编程用参数传递,而没有把使用频率高或复杂参数抽象为一个对象,很好的OOP代码组织结构可以取代局部变量的传递。

    至于文件读取的问题,使用file_get_content属于比较偷懒的做法,简单但是执行效率低,个人写脚本OK,项目中并不推荐。好的文件读取方式应该是

    if ($fh = fopen($filename, "r")) {
    # Processing
    fclose($fh);
    }


    一次IO操作同时包含了文件的正确性检查。参看《用 PHP 读取文件的正确方法》 http://www.ibm.com/developerworks/cn/opensource/os-php-readfiles/index.html
    Js
        10
    Js  
       2013-04-29 14:27:42 +08:00
    @raincious 这测试没什么意思, 同一个文件第一次就进OS缓存了, 等于单向的测file_exists+is_readable的效率, 尤其是is_readable本身就带了file_exists的功能...

    http://pastebin.com/U9ye5kQz
    GTim
        11
    GTim  
       2013-04-29 14:30:01 +08:00
    人家是看到你还没达到大牛水平,哈哈...

    错误和警告不能因为关闭了错误提示就忽略不是..
    cute
        12
    cute  
       2013-04-29 14:36:04 +08:00
    我所有的代码都是error_reporting(E_ALL | E_STRICT).
    chenz
        13
    chenz  
       2013-04-29 14:48:07 +08:00   ❤️ 1
    1. 这里所有的讨论,从来就没有人说要用isset来防止global污染。实际上,就我个人而言,自动全局变量,在至少五年前已经不需要讨论了。现在还有人在讨论自动全局变量,在我看来很不可思议

    2. 你提到"这可是E_WARNING啊,如果不屏蔽,报错给用户不说",证明你根本不知道error log应该如何设置。因为有经验的开发团队,在任何情况下,都不会让用户看到错误报告

    3. 你不能根据一个例子没有问题,就假定所有情况下都没有问题。所以单单根据你那个request来讨论是否应该开启notice或者是否该使用isset是没有任何意义的。为什么要开启notice,我之前已经说得很清楚了,你不能保证所有人,以及所有场景下,都能严格初始化变量

    4. 看了你写的inc.initializer.php,把最后的?>去掉吧。请看这里: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md The closing ?> tag MUST be omitted from files containing only PHP.

    5. 不知道你为何多次提及"新手"或者"新学"。犯了上面第四条的人,很明显不能算是个非常有经验的PHP开发人员。而我要告诉你,这个帖子里的回复者里,有发布过多个PECL项目的程序员,有超过10年经验的开发者,有对zval了如指掌的同学。所以,低调吧,在你还在犯4这样的错误,还在连zval是什么都不知道的情况下,不要妄谈什么"新手"的习惯
    chenz
        14
    chenz  
       2013-04-29 15:02:40 +08:00
    看了你的http://pastebin.com/i0ajTvMf

    1. 请了解clearstatcache这个函数,修改你的测试吧。你的测试代码没有任何意义
    2. 你又犯了?>的错误:https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
    breeswish
        15
    breeswish  
       2013-04-29 15:07:02 +08:00 via Android
    我一般开发环境使用E_ALL
    生产环境关闭错误显示

    检查变量是否为空什么的我觉得就跟C里面检查一个指针是否为NULL一样重要
    raincious
        16
    raincious  
    OP
       2013-04-29 15:21:36 +08:00
    事实证明,@AlloVince的结果是最快的,在各种情况下:

    T1: file_existe
    T2: file_get_content
    T3: @chenz & @Js 的方式
    T4: @AlloVince 的方式

    Array
    (
    [Looped] => 7500
    [Test1] => Array
    (
    [LastStartTime] => 1367219062.6647
    [LastEndTime] => 1367219062.6648
    [LastUsedTime] => 0.0001220703125
    [AvaTime] => 0.00010805782386953
    [Total] => 0.7269139289856
    )

    [Test2] => Array
    (
    [LastStartTime] => 1367219062.6648
    [LastEndTime] => 1367219062.665
    [LastUsedTime] => 0.00015997886657715
    [AvaTime] => 0.00016230891026936
    [Total] => 3.4872250556946
    )

    [Test3] => Array
    (
    [LastStartTime] => 1367219062.665
    [LastEndTime] => 1367219062.6654
    [LastUsedTime] => 0.0004270076751709
    [AvaTime] => 0.00042835394322712
    [Total] => 2.5338525772095
    )

    [Test4] => Array
    (
    [LastStartTime] => 1367219062.6654
    [LastEndTime] => 1367219062.666
    [LastUsedTime] => 0.00052094459533691
    [AvaTime] => 0.00033806347033363
    [Total] => 1.6245625019073
    )

    )

    这是代码:http://pastebin.com/gu7MSFRz

    但是除了Test3,和用来参考的Test1其他方式都至少可能会有E_WARNING抛出的风险。

    另外@chenz,我没有质疑各位的历史。当然也不在乎各位是否写过zval之类,一个工具而已。就事论事,你看清我的观点,我认为你应当error_reporting(0),以上所有各位我的观点都是如此,但是同时必须使用set_error_handler()。这是我的核心观点。也是我在开发时一直的观点。

    https://code.google.com/p/faculaframework/source/browse/trunk/include/class.oops.php#86

    我同时也没有说“就应该让错误看不见”。你也要注意这一点,不要没事挑刺。另外,我搬出新学,是因为我一开始也用的E_ALL,我代码的r2版本里你能看到一堆file_exist和isset,但是后来,这些错误扰乱了我正常的HTTP HEADER,于是我必须做出调整,保持程序在任何情况下都是稳定的。于是我固执的认为error_reporting这种事情就应该 = 0,然后你自己负责的好好处理,不要直接抛出。

    我想我的处理方式不在各位之下吧?

    当然,为了证明上述,于是我搬了一些论据,比如isset的开销。当然,@AlloVince的方法确实是最快的,条件允许我会将一些地方的file_exist改成fopen来追求速度。

    但是到此为止,我只看到了我的观点,没看到各位什么观点,我想知道你们开了E_ALL,然后怎么处理?就让错误飘在页面上?
    allenhsu
        17
    allenhsu  
       2013-04-29 15:51:22 +08:00
    @raincious 我是新手,但是 E_ALL 和『飘在页面上』好像是两回事。
    Js
        18
    Js  
       2013-04-29 15:51:23 +08:00
    @raincious 你那个例子不确定因素太多了, 比如./test/1.txt的大小, 毕竟你file_get_contents测的全部文件, 而后者是读取的是filesize('./test/1.txt')大小.(PS: 我不认为读取大段或者全部数据fopen再fread比file_get_contents高, 两者逻辑基本一样, 后者比前者少了几次函数调用+内存再分配+字符窜拼接,只会快不会慢的).

    言归正题, 文件不存在fopen一样会报warnning, 所以,按照你之前的思路, 你必须继续@fopen或者关掉警告, 至于性能,你可以把我那个例子的file_get_contents改成fopen, 差异还是那么大, 不会变的, 所以, 对待无法确定是否存在的文件, 还是在操作前判断是否存在
    qq286735628
        19
    qq286735628  
       2013-04-29 15:51:41 +08:00
    @raincious
    开发环境全部打开,至于这个提示出现在哪里,看个人爱好。
    生产环境写入日志,页面上不会出现任何额外的东西。
    shiny
        20
    shiny  
       2013-04-29 15:52:42 +08:00
    个人的习惯是开 E_ALL,像 file_get_contents 这类错误就用 @ 来屏蔽,error_handler 里可以识别是否是用 @ 屏蔽的。如果是 @ 屏蔽的则跳过,非 @ 屏蔽的则记录日志。错误级别足够高则显示自定义的 500 页面。

    所以平时都不可能出现「错误飘在页面上」。
    chenz
        21
    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
        22
    raincious  
    OP
       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
        23
    python  
       2013-04-29 17:15:21 +08:00   ❤️ 1
    @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
        24
    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
        25
    raincious  
    OP
       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
        26
    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
        27
    raincious  
    OP
       2013-04-29 20:26:02 +08:00
    @chenz,建议你语气和蔼点,像我,呵呵。

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

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

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

    4,?>,我觉得我的解决方案更好,于是我还是坚持自己的,这倒不是不理解,有人说?>不要更安全(为什么呢?),有人说?>不要可以避免白空间问题。但是,我没有白空间问题啊。
    chenz
        28
    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
        29
    chenz  
       2013-04-29 21:23:07 +08:00
    另外,对于4. "这倒不是不理解"。你完全没理解,如果你理解,就不会说"有人说"。

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

    我也down了一个
    maomaosang
        32
    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
        33
    rqrq  
       2013-04-29 23:07:43 +08:00
    我认为程序员必须遵守墨菲定律,lz觉得如何?
    多少年的开发经验不能证明任何问题。译言网有篇讲逻辑的文章,推荐lz阅读。
    dorentus
        34
    dorentus  
       2013-04-29 23:49:43 +08:00   ❤️ 1
    SO 上给答案减分的话是扣分人和被扣分人各减一分的
    你这个 0+ 5- 的结果本身已经可以说明问题了
    allenhsu
        35
    allenhsu  
       2013-04-30 00:05:59 +08:00
    @chenz @python
    我是 PHP 小白,关于这个 isset 的问题,想请教一下:如果先设置一个 defaultOptions 的 array,然后 array_merge(defaultOptions, $_GET),后面就不检查 isset 直接使用,这种方法是否合理?对效率的影响大不大?
    raincious
        36
    raincious  
    OP
       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
        37
    raincious  
    OP
       2013-04-30 00:38:13 +08:00
    @allenhsu

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

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

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

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

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

    尊重事实,客观、虚心、耐心,我觉得是一名程序员的基本素养。
    laoyuan
        41
    laoyuan  
       2013-04-30 10:13:06 +08:00
    可能LZ同事啥的也上v2ex,面子上过不去。。。
    raincious
        42
    raincious  
    OP
       2013-04-30 11:26:28 +08:00 via Android
    @laoyuan 还真不在。我对我自己的代码要求很严,但是对notice我是有选择处理,不是每一个notice都做屏蔽,比如如果if ($a == 'yes') 这样后面不会导致问题,那就这样好了。

    说真的,我写过的代码中,从来没有因为undefined index或变量出过任何问题。所以我当然认为,关键在于你知道这个notice怎么来的,会导致什么,要如何控制,之后你怎么处理才不会导致问题是你自己的事。

    当然,大家建议去掉所有导致的问题我已经了解了,事实上@AlloVince对notice已经解释的很明白,配合@python的例子,对我来说已经形成了处理的Pattern。

    当然,我觉得这个帖子从一开始已经变味,我并不是在讨论是不是要彻底不管errors,而是处理方式的问题罢了。

    @Leask 我真的很耐心,只是回复的信息对我来说还没形成体系才一再追问罢了。Pattren(How)有了,但是Why不完整,所以我才对回答不满意。比如我说8楼,几个表达式效果是一样的,这个问题就无人涉及,是不是因为在反正不能让notice出现这一前提下,大家都无视了那个问题呢。

    我真心希望是你回答了我的问题。谢谢。
    ShiningRay
        43
    ShiningRay  
       2013-04-30 12:33:04 +08:00
    楼主如果你发这贴是为了寻找认可和共鸣我觉得就错了。

    可能楼主剑走偏锋,有自己的一套打法,但你的经验可能适合你的工作环境,对别人来说则可能不合适,最后站在不一样的立场上进行讨论,最后讨论只能变味。

    所以,你应该把自己的方法论给完整的梳理一遍,可以考虑自己写一个系列的文章,把自己的经验总结一下,让大家明白和清楚。


    简单的说,等你出名了自然有人捧你。
    Leask
        44
    Leask  
       2013-04-30 12:33:11 +08:00 via iPad   ❤️ 1
    有时候我们不但要考虑代码在小范围内是否流畅运行。当然,这和你参与项目的规模和复杂程度有关。我留意到你提到你是写框架的。我在连续两家公司是做后端框架的。你应该知道很多时候你不能完全预料一切的input都是可以预料的。如果在框架层不能做到 notice free 的话,我觉得代码是没有达到要求的。至于你说你也对代码要求也很高,我只能说不同的人对「高」的理解不一样。

    其次,作为越靠近后方的开发者,你必须明白自己提供的基础设施必须是尽可能可靠的。那么,你处理异常的方式应该尽可能地符合「最佳实践」这样有助于你的同事和你提供的api的「开发者用户」更能理解。

    鉴于这几点,真的不要问 why 了。
    Cadina
        45
    Cadina  
       2013-04-30 12:37:46 +08:00
    大家不要再喷LZ了,LZ是来卖萌的。。
    (把NOTICE关掉,我看不见啊,看不见~~)
    davepkxxx
        46
    davepkxxx  
       2013-04-30 12:39:57 +08:00
    这就和Java里不论什么情况,直接把异常给捕获,也不给交代,或者直接网上抛差不多。
    raincious
        47
    raincious  
    OP
       2013-04-30 16:43:40 +08:00
    @Leask 刚才尝试下将我框架内的Notice修补,由于我用数组很多,很多数组在类里面 public $array = array(); 就好了,之后就动态使用,需要时判断,所以很多Undefined Index。

    但是改掉这些之后,目前看来没什么收益,当然也没什么损失,可能是因为框架比较老的缘故,还有待观察。我写这个框架的时候Discuz还是7,也有一堆堆的Undefined,Wordpress里面当时也是一堆Undefined,phpBB里面也是一堆Undefined、IPB和VBB里也是一堆Undefined。于是这么多Undefined,我对Undefined也就没感觉了,觉得就应该这样。

    反正目前正在准备新框架了,因为目前的框架是为规模不大的网站设计的,很多东西没有灵活的考虑到,比如插件、PDO和ORM之类。新框架写的时候会注意Undefined这样的问题。目前的架构处于稳定性考虑就先如此好了。

    现在Wordpress用新架构之后倒是没有多少Notice了,可能去掉Notice这是趋势吧。用新的OO风格去写,可能本身Notice也不会很多。
    evlos
        48
    evlos  
       2013-04-30 22:48:08 +08:00
    恩,没人能 100% 保证自己这辈子不会做什么事情,也没人能 100% 保证自己有一天不会手滑而且手滑的时候不会造成巨大的损失,所以大家的建议都是关于尽量地养成不留隐患的好习惯。

    我的习惯主要是一般数组都要看看 index 是否存在,文件也得看看是否存在,变量如果初始化了一般不用管,但是用户输入的一定要看看 $_POST['xxx'] 之类的有没有输入进来,输入进来之后最好拿正则式检查一遍。

    开发环境一定 E_ALL | E_STRICT。
    生产环境 E_ALL & ~E_DEPRECATED,display_error 关掉。
    日志非常重要,大型网站一般配备日志服务器,可以从此看出日志的重要性,就算不重要的日志,也可能成为某些隐患。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3112 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 13:17 · PVG 21:17 · LAX 05:17 · JFK 08:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.