写了这么久PHP,在心血来潮在StackOverflow上回答了别人PHP的问题,没想到被扣分还说没常识,求研判。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
raincious
V2EX    PHP

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

  •  
  •   raincious 2013-04-29 12:40:51 +08:00 11340 次点击
    这是一个创建于 4547 天前的主题,其中的信息可能已经有所发展或是发生改变。
    这是我回答的地址:
    http://stackoverlow.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
    yemoluo
        11
    yemoluo  
       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里面有个东西叫做diplay_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-0430 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     Solana     2213 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 16:07 PVG 00:07 LAX 09:07 JFK 12:07
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86