PHP解析/语法错误;如何解决它们

770
每个人都会遇到语法错误,即使是经验丰富的程序员也会打错字。对于新手来说,这只是学习过程的一部分。然而,常常很容易解释错误消息,例如:

PHP Parse error: syntax error, unexpected '{' in index.php on line 20

意外的符号并不总是真正的罪魁祸首。但是行号给出了大致的查找起点。

始终查看代码上下文。语法错误通常隐藏在所提及的以及先前的代码行中。将您的代码与手册中的语法示例进行比较。

虽然不是每种情况都相同,但有一些解决语法错误的一般步骤。此参考摘要了常见的陷阱:

2
这并不足以成为答案,但可以使用parsekit_compile_string编写分析器,并在其中放置更友好的答案。 如果集成到您的IDE中,这可能会非常有用。 - Owen Beresford
7
你在这方面付出了大量的工作,值得尊敬。这对于教师学会快速指出错误或是创建IDE或实现快速修复非常有益。然而,正如@Panique所建议的那样,IDE已经能够很好地为你完成大部分工作。此外,在许多情况下,从头开始可能是一个不错的选择。 - allprog
2
@Fred-ii- 我认为大多数原因类似于 T_IF / T_FOREACH / ... 块。尽管我想编译一个更定制的 IF/ELSE/ELSEIF 问题摘要。 - mario
3
我知道,当我多年前学习PHP时,我希望有这份清单。对于初学者来说非常有用。 - user10957435
2
@β.εηοιτ.βε 很棒的想法;最近有相当多这样的问题。如果可能的话,它需要涵盖三种常见情况(导入范围、特性、闭包)。 - mario
显示剩余12条评论
20个回答

324

什么是语法错误?

PHP属于C风格命令式编程语言。它有严格的语法规则,当遇到错放的符号或标识符时无法恢复。它无法猜测您的编码意图。

Function definition syntax abstract

最重要的提示

您可以始终采取一些基本预防措施:

  • 使用适当的代码缩进或采用任何高峰值编码风格。可读性可以避免不规则。

  • 使用带有语法高亮的 PHP IDE 或编辑器。这也有助于括号/方括号平衡。

    Expected: semicolon

  • 阅读语言参考和手册中的示例。两次,以成为相当熟练。

如何解释解析器错误

典型的语法错误消息如下:

Parse error: syntax error, unexpected T_STRING, expecting ';' in file.php on line 217

这列出了可能的语法错误位置。请查看所提到的文件名和行号。

T_STRING这样的标记解释了解析器/分词器最终无法处理的符号。然而,这不一定是语法错误的原因。

同样重要的是要查看之前的代码行。通常,语法错误只是早期发生的差错。错误行号只是解析器放弃处理所有内容的地方。

解决语法错误

有许多方法可以缩小范围并修复语法问题。

  • 打开所提到的源文件。查看所提到的代码行

    • 对于跑掉的字符串和错位的运算符,通常这就是你找到问题的地方。

    • 从左到右阅读该行,并想象每个符号的作用。

  • 通常还需要查看前面的行

    • 特别是,在先前的行末/语句处缺少分号;。 (至少从风格的角度来看。)

    • 如果{代码块}错误关闭或嵌套,则可能需要进一步调查源代码。使用适当的代码缩进来简化此过程。

  • 看看语法着色

    • 字符串、变量和常量应具有不同的颜色。

    • 操作符+-*/.也应该有不同的颜色。否则它们可能处于错误的上下文中。

    • 如果您看到字符串颜色扩展太远或太短,则表示您找到了未转义或缺少的关闭"'字符串标记。

    • 如果两个相同颜色的标点符号相邻,则也可能会出现问题。通常,如果不是跟随运算符的 ++ --或括号,则操作符是孤立的。在大多数情况下,直接跟随彼此的两个字符串/标识符是不正确的。

  • 空格是你的朋友。 遵循任何编码风格。

  • 暂时打破长行。

    • 您可以在运算符或常量和字符串之间自由添加换行符。然后,解析器将具体化解析错误的行号。而不是查看非常冗长的代码,您可以隔离缺失或放错的语法符号。

    • 将复杂的if语句分成单独或嵌套的if条件。

    • 使用临时变量简化代码而不是冗长的数学公式或逻辑链。 (更易读=更少的错误。)

    • 在以下内容之间添加换行符:

      1. 您可以轻松确认为正确的代码,
      2. 您不确定的部分,
      3. 解析器抱怨的行。

      将长代码块划分为分区真的很有助于找到语法错误的来源。

  • 注释掉冒犯性代码。

    • 如果无法隔离问题源,则开始注释(因此暂时删除)代码块。

    • 一旦摆脱了解析错误,您就找到了问题源。在那里仔细寻找。

    • 有时候,您想要暂时删除完整的函数/方法块。 (在大括号不匹配和缩进错误的情况下。)

      谷歌您的错误信息。语法符号不易搜索(Stack Overflow本身被SymbolHound索引)。因此,在找到相关内容之前,可能需要查看更多页面。
      更进一步的指南:

      白屏死机

      如果你的网站仅显示空白页面,则通常是由于语法错误导致的。 可以通过以下方式启用错误显示:

      • error_reporting = E_ALL
      • display_errors = 1

      php.ini文件中进行设置,或者通过.htaccess文件进行mod_php设置, 甚至可以使用FastCGI设置的.user.ini文件。

      在破损的脚本中启用它已经太晚了,因为PHP甚至无法解释/运行第一行。一个快速的解决方法是创建一个包装脚本,比如test.php

      <?php
         error_reporting(E_ALL);
         ini_set("display_errors", 1);
         include("./broken-script.php");
      

      然后通过访问这个包装脚本来调用失败的代码。

      当脚本崩溃并出现HTTP 500响应时,启用PHP的error_log并查看Web服务器的error.log也会有所帮助。


在早期版本的PHP中,使用error_reporting(E_ALL | E_STRICT); - Geo
3
有些集成开发环境(如NetBeans)不仅支持语法高亮,还支持代码格式化。如果你养成了正确格式化代码并时不时地让IDE重新格式化的习惯,可能会发现一些难以发现的问题,比如未匹配的括号。 - Josep Valls

119

我认为这个主题已经被过度讨论和复杂化了。使用IDE是完全避免任何语法错误的方法。我甚至会说,没有使用IDE的工作方式有点不专业。为什么呢?因为现代IDE在你输入每个字符后都会检查你的语法。当你编写代码并且整行都变成红色,并显示一个大的警告通知,告诉你确切的类型和语法错误的精确位置时,就绝对没有必要再去寻找另一种解决方案。

使用语法检查的IDE意味着:

你(实际上)永远不会再遇到语法错误,因为你在键入时就能看到它们。真的。

具有语法检查的优秀IDE(所有这些都可用于Linux、Windows和Mac):

  1. NetBeans [免费]
  2. PHPStorm [199美元]
  3. Eclipse with PHP Plugin [免费]
  4. Sublime [80美元](主要是文本编辑器,但可通过插件扩展,如PHP Syntax Parser

3
当然可以。然而,重新列举IDE,你能否详细解释一下它们在语法帮助方面的区别呢?Sublime大多是编辑器,而不是IDE;但更漂亮和迅速;主要进行语法高亮,但在括号匹配方面也非常可靠。例如,它可以立即发现T_CONSTANT_AND_ENCAPSED错误,而PHPStorm则不行;但是PHPStorm在内联错误方面会有更多的波浪线提示。NetBeans的语法提示过去比PHP的还要晦涩(只是重新列举了允许的结构)。你能分享一下您的优缺点体验吗?您最喜欢的是Eclipse/PDT还是其他软件? - mario
@mario,我觉得你对这个话题非常深入,所以我真的不想在这里说错什么,但是我和我的团队成员、编程朋友、自由职业合作伙伴所写的所有代码都从未在IDE中执行时出现语法错误。因此,我认为至少Netbeans/PHPStorm的语法检查非常强大。但也许我误解了你的问题。给我几个小时... ;) - Sliq
你的答案已经十分准确。它能回答我们99%的问题。然而,在这个背景下,我想对“哪个IDE提供更适合新手的工具提示”做一些权衡考虑。如果你已经熟悉了,颜色标记和波浪线可能已经足够了,但是我认为对于初学者来说,这些差异可能更加显著。 - mario
有时IDE不是一个可行的选择。例如,在WordPress主题或插件中进行快速编辑。是的,我可以将所有代码复制到IDE中,但那样我就得打开它,将所有内容粘贴进去,设置头文件和其他浪费时间的东西,而我只是希望进行快速编辑。现在,如果你正在开发新功能或从头开始,那么,在IDE中完成。最好在开始时花点额外的时间来设置它,这样你不会后悔。 - user1934286
1
@SimaoGomesViana 对于我的网站,我有一个本地实例,并在Sublime中进行编辑。但是当朋友打电话时,或者我正在尝试一个还没有真正上线的新网站时,我会直接在服务器上进行编辑。如果我担心它,我会在本地备份文件,但我也在服务器上备份了它。哈哈。我只是想说,有时候快速而肮脏并没有什么问题。 - user1934286
显示剩余2条评论

61

意料之外的 [

近年来,在过时的PHP版本中,常常出现意料之外的[数组括号。自PHP>= 5.4起,短数组语法已经可用。旧版安装仅支持array()

$php53 = array(1, 2, 3);
$php54 = [1, 2, 3];
         ⇑

对于较旧的PHP版本,数组函数结果解引用也不可用:

$result = get_whatever()["key"];
                      ⇑

参考 - PHP中出现的“语法错误,意外的\[”,显示了最常见和实用的解决方法。

不过,你最好升级你的PHP安装版本。对于共享Web托管计划,首先研究是否可以使用例如SetHandler php56-fcgi来启用较新的运行时。

另请参见:

顺便提一下,如果你真的喜欢旧的+较慢的PHP版本,则还有预处理器和PHP 5.4语法向下转换程序

意外的[语法错误的其他原因

如果不是PHP版本不匹配,那么往往是普通的拼写错误或新手语法错误:

  • You can't use array property declarations/expressions in classes, not even in PHP 7.

    protected $var["x"] = "Nope";
  • Confusing [ with opening curly braces { or parentheses ( is a common oversight.

    foreach [$a as $b)
            
    

    Or even:

    function foobar[$a, $b, $c] {
                   ⇑
    
  • Or trying to dereference constants (before PHP 5.6) as arrays:

    $var = const[123];
           ⇑
    

    At least PHP interprets that const as a constant name.

    If you meant to access an array variable (which is the typical cause here), then add the leading $ sigil - so it becomes a $varname.

  • You are trying to use the global keyword on a member of an associative array. This is not valid syntax:

    global $var['key'];
    

意外的]闭合方括号

这种情况比较少见,但在终止数组时也可能出现语法错误,即使用了多余的]方括号。

  • Again mismatches with ) parentheses or } curly braces are common:

    function foobar($a, $b, $c] {
                              ⇑
    
  • Or trying to end an array where there isn't one:

    $var = 2];
    

    Which often occurs in multi-line and nested array declarations.

    $array = [1,[2,3],4,[5,6[7,[8],[9,10]],11],12]],15];
                                                 ⇑
    

    If so, use your IDE for bracket matching to find any premature ] array closure. At the very least use more spacing and newlines to narrow it down.


上面的链接“PHP 5.4语法降级器”https://github.com/IonutBajescu/short-arrays-to-long-arrays已经失效。 - DanimalReks
"function foobar[$a, $b, $c] {" 我以为函数的声明应该像 "function foobar($a, $b, $c){" 一样???" - Yunfei Chen

50

未预料到的T_VARIABLE

"未预料到的T_VARIABLE"意味着有一个文本字面量$variable名称,它不能适应当前的表达式/语句结构。

purposefully abstract/inexact operator+$variable diagram

  1. Missing semicolon

    It most commonly indicates a missing semicolon in the previous line. Variable assignments following a statement are a good indicator where to look:

            ⇓
     func1()
     $var = 1 + 2;     # parse error in line +2
    
  2. String concatenation

    A frequent mishap are string concatenations with forgotten . operator:

                                    ⇓
     print "Here comes the value: "  $value;
    

    Btw, you should prefer string interpolation (basic variables in double quotes) whenever that helps readability. Which avoids these syntax issues.

    String interpolation is a scripting language core feature. No shame in utilizing it. Ignore any micro-optimization advise about variable . concatenation being faster. It's not.

  3. Missing expression operators

    Of course the same issue can arise in other expressions, for instance arithmetic operations:

                ⇓
     print 4 + 7 $var;
    

    PHP can't guess here if the variable should have been added, subtracted or compared etc.

  4. Lists

    Same for syntax lists, like in array populations, where the parser also indicates an expected comma , for example:

                                           ⇓
     $var = array("1" => $val, $val2, $val3 $val4);
    

    Or functions parameter lists:

    function myfunc($param1, $param2 $param3, $param4)
    

    Equivalently do you see this with list or global statements, or when lacking a ; semicolon in a for loop.

  5. Class declarations

    This parser error also occurs in class declarations. You can only assign static constants, not expressions. Thus the parser complains about variables as assigned data:

     class xyz {      ⇓
         var $value = $_GET["input"];
    

    Unmatched } closing curly braces can in particular lead here. If a method is terminated too early (use proper indentation!), then a stray variable is commonly misplaced into the class declaration body.

  6. Variables after identifiers

    You can also never have a variable follow an identifier directly:

                  ⇓
     $this->myFunc$VAR();
    

    Btw, this is a common example where the intention was to use variable variables perhaps. In this case a variable property lookup with $this->{"myFunc$VAR"}(); for example.

    Take in mind that using variable variables should be the exception. Newcomers often try to use them too casually, even when arrays would be simpler and more appropriate.

  7. Missing parentheses after language constructs

    Hasty typing may lead to forgotten opening or closing parenthesis for if and for and foreach statements:

            ⇓
     foreach $array as $key) {
    

    Solution: add the missing opening ( between statement and variable.

                           ⇓
     if ($var = pdo_query($sql) {
          $result = …
    

    The curly { brace does not open the code block, without closing the if expression with the ) closing parenthesis first.

  8. Else does not expect conditions

         ⇓
    else ($var >= 0)
    

    Solution: Remove the conditions from else or use elseif.

  9. Need brackets for closure

    function() use $var {}
    

    Solution: Add brackets around $var.

  10. Invisible whitespace

    As mentioned in the reference answer on "Invisible stray Unicode" (such as a non-breaking space), you might also see this error for unsuspecting code like:

    <?php$var = new PDO(...);
    

    It's rather prevalent in the start of files and for copy-and-pasted code. Check with a hexeditor, if your code does not visually appear to contain a syntax issue.

参见


32

意外的T_CONSTANT_ENCAPSED_STRING错误
意外的T_ENCAPSED_AND_WHITESPACE错误

T_CONSTANT_ENCAPSED_STRINGT_ENCAPSED_AND_WHITESPACE这些笨重的名称是指引号括起来的"字符串"文字。

它们在不同的上下文中使用,但语法问题非常相似。在双引号字符串上下文中会出现T_ENCAPSED…警告,而T_CONSTANT…字符串通常会在纯PHP表达式或语句中迷失。

  1. Incorrect variable interpolation

    And it comes up most frequently for incorrect PHP variable interpolation:

                              ⇓     ⇓
    echo "Here comes a $wrong['array'] access";
    

    Quoting arrays keys is a must in PHP context. But in double quoted strings (or HEREDOCs) this is a mistake. The parser complains about the contained single quoted 'string', because it usually expects a literal identifier / key there.

    More precisely it's valid to use PHP2-style simple syntax within double quotes for array references:

    echo "This is only $valid[here] ...";
    

    Nested arrays or deeper object references however require the complex curly string expression syntax:

    echo "Use {$array['as_usual']} with curly syntax.";
    

    If unsure, this is commonly safer to use. It's often even considered more readable. And better IDEs actually use distinct syntax colorization for that.

  2. Missing concatenation

    If a string follows an expression, but lacks a concatenation or other operator, then you'll see PHP complain about the string literal:

                           ⇓
    print "Hello " . WORLD  " !";
    

    While it's obvious to you and me, PHP just can't guess that the string was meant to be appended there.

  3. Confusing string quote enclosures

    The same syntax error occurs when confounding string delimiters. A string started by a single ' or double " quote also ends with the same.

                    ⇓
    print "<a href="' . $link . '">click here</a>";
          ⌞⎽⎽⎽⎽⎽⎽⎽⎽⌟⌞⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⌟⌞⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⎽⌟
    

    That example started with double quotes. But double quotes were also destined for the HTML attributes. The intended concatenation operator within however became interpreted as part of a second string in single quotes.

    Tip: Set your editor/IDE to use slightly distinct colorization for single and double quoted strings. (It also helps with application logic to prefer e.g. double quoted strings for textual output, and single quoted strings only for constant-like values.)

    This is a good example where you shouldn't break out of double quotes in the first place. Instead just use proper \" escapes for the HTML attributes´ quotes:

    print "<a href=\"{$link}\">click here</a>";
    

    While this can also lead to syntax confusion, all better IDEs/editors again help by colorizing the escaped quotes differently.

  4. Missing opening quote

    Equivalently are forgotten opening "/' quotes a recipe for parser errors:

                   ⇓
     make_url(login', 'open');
    

    Here the ', ' would become a string literal after a bareword, when obviously login was meant to be a string parameter.

  5. Array lists

    If you miss a , comma in an array creation block, the parser will see two consecutive strings:

    array(               ⇓
         "key" => "value"
         "next" => "....",
    );
    

    Note that the last line may always contain an extra comma, but overlooking one in between is unforgivable. Which is hard to discover without syntax highlighting.

  6. Function parameter lists

    The same thing for function calls:

                             ⇓
    myfunc(123, "text", "and"  "more")
    
  7. Runaway strings

    A common variation are quite simply forgotten string terminators:

                                    ⇓
    mysql_evil("SELECT * FROM stuffs);
    print "'ok'";
          ⇑
    

    Here PHP complains about two string literals directly following each other. But the real cause is the unclosed previous string of course.

  8. HEREDOC indentation

    Prior PHP 7.3, the heredoc string end delimiter can't be prefixed with spaces:

    print <<< HTML
        <link..>
        HTML;
       ⇑
    

    Solution: upgrade PHP or find a better hoster.

参见


30

意外的 T_STRING

T_STRING 有点误导性,它并不是指带引号的 "字符串"。它是指遇到了未处理的标识符,这可能涉及从裸单词到残留的 CONSTANT 或函数名称、忘记加引号的字符串或任何纯文本。

  1. Misquoted strings

    This syntax error is most common for misquoted string values however. Any unescaped and stray " or ' quote will form an invalid expression:

                   ⇓                  ⇓
     echo "<a href="http://example.com">click here</a>";
    

    Syntax highlighting will make such mistakes super obvious. It's important to remember to use backslashes for escaping \" double quotes, or \' single quotes - depending on which was used as string enclosure.

    • For convenience you should prefer outer single quotes when outputting plain HTML with double quotes within.
    • Use double quoted strings if you want to interpolate variables, but then watch out for escaping literal " double quotes.
    • For lengthier output, prefer multiple echo/print lines instead of escaping in and out. Better yet consider a HEREDOC section.


    Another example is using PHP entry inside HTML code generated with PHP:

    $text = '<div>some text with <?php echo 'some php entry' ?></div>'
    

    This happens if $text is large with many lines and developer does not see the whole PHP variable value and focus on the piece of code forgetting about its source. Example is here

    See also What is the difference between single-quoted and double-quoted strings in PHP?.

  2. Unclosed strings

    If you miss a closing " then a syntax error typically materializes later. An unterminated string will often consume a bit of code until the next intended string value:

                                                           ⇓
    echo "Some text", $a_variable, "and some runaway string ;
    success("finished");
             ⇯
    

    It's not just literal T_STRINGs which the parser may protest then. Another frequent variation is an Unexpected '>' for unquoted literal HTML.

  3. Non-programming string quotes

    If you copy and paste code from a blog or website, you sometimes end up with invalid code. Typographic quotes aren't what PHP expects:

    $text = ’Something something..’ + ”these ain't quotes”;
    

    Typographic/smart quotes are Unicode symbols. PHP treats them as part of adjoining alphanumeric text. For example ”these is interpreted as a constant identifier. But any following text literal is then seen as a bareword/T_STRING by the parser.

  4. The missing semicolon; again

    If you have an unterminated expression in previous lines, then any following statement or language construct gets seen as raw identifier:

           ⇓
    func1()
    function2();
    

    PHP just can't know if you meant to run two functions after another, or if you meant to multiply their results, add them, compare them, or only run one || or the other.

  5. Short open tags and <?xml headers in PHP scripts

    This is rather uncommon. But if short_open_tags are enabled, then you can't begin your PHP scripts with an XML declaration:

    <?xml version="1.0"?>
    

    PHP will see the <? and reclaim it for itself. It won't understand what the stray xml was meant for. It'll get interpreted as constant. But the version will be seen as another literal/constant. And since the parser can't make sense of two subsequent literals/values without an expression operator in between, that'll be a parser failure.

  6. Invisible Unicode characters

    A most hideous cause for syntax errors are Unicode symbols, such as the non-breaking space. PHP allows Unicode characters as identifier names. If you get a T_STRING parser complaint for wholly unsuspicious code like:

    <?php
        print 123;
    

    You need to break out another text editor. Or an hexeditor even. What looks like plain spaces and newlines here, may contain invisible constants. Java-based IDEs are sometimes oblivious to an UTF-8 BOM mangled within, zero-width spaces, paragraph separators, etc. Try to reedit everything, remove whitespace and add normal spaces back in.

    You can narrow it down with with adding redundant ; statement separators at each line start:

    <?php
        ;print 123;
    

    The extra ; semicolon here will convert the preceding invisible character into an undefined constant reference (expression as statement). Which in return makes PHP produce a helpful notice.

  7. The `$` sign missing in front of variable names

    Variables in PHP are represented by a dollar sign followed by the name of the variable.

    The dollar sign ($) is a sigil that marks the identifier as a name of a variable. Without this sigil, the identifier could be a language keyword or a constant.

    This is a common error when the PHP code was "translated" from code written in another language (C, Java, JavaScript, etc.). In such cases, a declaration of the variable type (when the original code was written in a language that uses typed variables) could also sneak out and produce this error.

  8. Escaped Quotation marks

    If you use \ in a string, it has a special meaning. This is called an "Escape Character" and normally tells the parser to take the next character literally.

    Example: echo 'Jim said \'Hello\''; will print Jim said 'hello'

    If you escape the closing quote of a string, the closing quote will be taken literally and not as intended, i.e. as a printable quote as part of the string and not close the string. This will show as a parse error commonly after you open the next string or at the end of the script.

    Very common error when specifiying paths in Windows: "C:\xampp\htdocs\" is wrong. You need "C:\\xampp\\htdocs\\".

  9. Typed properties

    You need PHP ≥7.4 to use property typing such as:

    public stdClass $obj;
    

19

意外的(

(通常跟随诸如if/foreach/for/array/list等语言结构或开始算术表达式。在"strings"、先前的()、孤立的$和某些典型的声明上下文之后,它们在语法上是不正确的。

  1. Function declaration parameters

    A rarer occurrence for this error is trying to use expressions as default function parameters. This is not supported, even in PHP7:

    function header_fallback($value, $expires = time() + 90000) {
    

    Parameters in a function declaration can only be literal values or constant expressions. Unlike for function invocations, where you can freely use whatever(1+something()*2), etc.

  2. Class property defaults

    Same thing for class member declarations, where only literal/constant values are allowed, not expressions:

    class xyz {                   ⇓
        var $default = get_config("xyz_default");
    

    Put such things in the constructor. See also Why don't PHP attributes allow functions?

    Again note that PHP 7 only allows var $xy = 1 + 2 +3; constant expressions there.

  3. JavaScript syntax in PHP

    Using JavaScript or jQuery syntax won't work in PHP for obvious reasons:

    <?phpprint $(document).text();
    

    When this happens, it usually indicates an unterminated preceding string; and literal <script> sections leaking into PHP code context.

  4. isset(()), empty, key, next, current

    Both isset() and empty() are language built-ins, not functions. They need to access a variable directly. If you inadvertently add a pair of parentheses too much, then you'd create an expression however:

              ⇓
    if (isset(($_GET["id"]))) {
    

    The same applies to any language construct that requires implicit variable name access. These built-ins are part of the language grammar, therefore don't permit decorative extra parentheses.

    User-level functions that require a variable reference -but get an expression result passed- lead to runtime errors instead.


意外的 )
  1. Absent function parameter

    You cannot have stray commas last in a function call. PHP expects a value there and thusly complains about an early closing ) parenthesis.

                  ⇓
    callfunc(1, 2, );
    

    A trailing comma is only allowed in array() or list() constructs.

  2. Unfinished expressions

    If you forget something in an arithmetic expression, then the parser gives up. Because how should it possibly interpret that:

                   ⇓
    $var = 2 * (1 + );
    

    And if you forgot the closing ) even, then you'd get a complaint about the unexpected semicolon instead.

  3. Foreach as constant

    For forgotten variable $ prefixes in control statements you will see:

                       ↓    ⇓
    foreach ($array as wrong) {
    

    PHP here sometimes tells you it expected a :: instead. Because a class::$variable could have satisfied the expected $variable expression..


意外的 {

花括号{}用于封闭代码块。有关它们的语法错误通常指示某些错误的嵌套。

  1. Unmatched subexpressions in an if

    Most commonly unbalanced ( and ) are the cause if the parser complains about the opening curly { appearing too early. A simple example:

                                  ⇓
    if (($x == $y) && (2 == true) {
    

    Count your parentheses or use an IDE which helps with that. Also don't write code without any spaces. Readability counts.

  2. { and } in expression context

    You can't use curly braces in expressions. If you confuse parentheses and curlys, it won't comply to the language grammar:

               ⇓
    $var = 5 * {7 + $x};
    

    There are a few exceptions for identifier construction, such as local scope variable ${references}.

  3. Variable variables or curly var expressions

    This is pretty rare. But you might also get { and } parser complaints for complex variable expressions:

                          ⇓
    print "Hello {$world[2{]} !";
    

    Though there's a higher likelihood for an unexpected } in such contexts.


意外的}

当出现"意外的}"错误时,您多半是提前关闭了一个代码块。

  1. Last statement in a code block

    It can happen for any unterminated expression.

    And if the last line in a function/code block lacks a trailing ; semicolon:

    function whatever() {
        doStuff()
    }            ⇧
    

    Here the parser can't tell if you perhaps still wanted to add + 25; to the function result or something else.

  2. Invalid block nesting / Forgotten {

    You'll sometimes see this parser error when a code block was } closed too early, or you forgot an opening { even:

    function doStuff() {
        if (true)    ⇦
            print "yes";
        }
    }   ⇧
    

    In above snippet the if didn't have an opening { curly brace. Thus the closing } one below became redundant. And therefore the next closing }, which was intended for the function, was not associable to the original opening { curly brace.

    Such errors are even harder to find without proper code indentation. Use an IDE and bracket matching.


意外出现 {,期望出现 (

需要一个条件/声明头和代码块的语言结构将触发此错误。

  1. Parameter lists

    For example misdeclared functions without parameter list are not permitted:

                     ⇓
    function whatever {
    }
    
  2. Control statement conditions

    And you can't likewise have an if without condition.

      ⇓
    if {
    }
    

    Which doesn't make sense, obviously. The same thing for the usual suspects, for/foreach, while/do, etc.

    If you've got this particular error, you definitely should look up some manual examples.


1
在这篇帖子中寻找我的问题答案,但最终自己找到了解决“Unexpected {”问题的方法,所以我想分享我的答案——对我来说,问题出在换行编码上——一些文件使用了Macintosh换行符,但当我将它们改为Windows换行符时,我的问题(在本地主机(WAMP)上一切正常,但在Linux Web服务器上不行)得到了解决。 - Edgars Aivars
@EdgarsAivars 谢谢您的评论!特定于平台的换行符确实是一个不常见且棘手的问题。我可能也会在这里提到它。 (它只是在其他参考答案中作为旁注提到的。) - mario
我发现出现“Unexpected }”的原因是我的代码中使用了php短标签<?而不是<?php - 在其他服务器上可以工作,所以找了一段时间才发现这个问题。 - c7borg

15

意外的 $end

当PHP提到“意外的$end”时,它意味着您的代码在解析器期望更多代码时结束了。(这个消息有点误导,如果字面上理解,它并不是关于一个名为“$end”的变量,有时新手会这么认为。它是指“文件结尾”,EOF。)

原因: 代码块、函数或类声明的{}不平衡。

它几乎总是关于缺少}大括号来关闭前面的代码块。它的意思是解析器希望找到一个闭合的},但实际上已经到达了文件的结尾。

  • 再次,使用适当的缩进来避免这些问题。

  • 使用带有括号匹配功能的IDE,找出}缺失的位置。 大多数IDE和文本编辑器都有键盘快捷键:

    • NetBeans,PhpStorm,Komodo:Ctrl[Ctrl]
    • Eclipse,Aptana:CtrlShiftP
    • Atom,Sublime:Ctrlm - Zend Studio CtrlM
    • Geany,Notepad++:CtrlB - Joe:CtrlG - Emacs:C-M-n - Vim:%

大多数IDE还会突出显示匹配的大括号、方括号和圆括号。 这使得检查它们之间的关系非常容易:

Bracket matching in an IDE

未结束的表达式

未结束的表达式或语句也会导致意外的 $end 语法/解析器错误:

  • $var = func(1, ?>EOF

所以,首先看一下脚本的末尾。在任何 PHP 脚本中,最后一个语句的末尾分号通常是多余的。但是你应该保留它。因为它可以缩小这种语法问题的范围。特别是当你发现自己在脚本末尾添加更多语句时。

缩进的 HEREDOC 标记

HEREDOC 或 NOWDOC字符串的另一个常见情况是,终止标记被忽略了,而有前导空格、制表符等:

print <<< END
    Content...
    Content....
  END;
# ↑ terminator isn't exactly at the line start

因此,解析器认为HEREDOC字符串将继续到文件的结尾(因此出现“意外的$end”)。几乎所有IDE和语法突出显示编辑器都会明显地或警告这一点。

转义引号

如果您在字符串中使用\,它具有特殊含义。这称为“ 转义字符”,通常告诉解析器将下一个字符视为字面值。

例如:echo 'Jim said \'Hello\''; 将打印Jim said 'hello'

如果您转义字符串的结束引号,则结束引号将被视为字面量,而不是预期的可打印引号,作为字符串的一部分而不是关闭字符串。这将在您打开下一个字符串或脚本末尾后常见地显示为解析错误。

在Windows中指定路径时非常常见的错误:"C:\xampp\htdocs\" 是错误的。您需要 "C:\\xampp\\htdocs\\"。或者,PHP通常会将Unix样式的路径(例如"C:/xampp/htdocs/")转换为Windows的正确路径。

替代语法

有时候在模板中使用语句/代码块的替代语法时,你可能会遇到这种语法错误。例如,使用 if:else:,但是缺少 endif;

另请参阅:


15

意外的T_IF
意外的T_ELSEIF
意外的T_ELSE
意外的T_ENDIF

条件控制块ifelseifelse遵循简单的结构。当您遇到语法错误时,很可能只是无效的块嵌套→缺少{花括号} - 或者多一个。

enter image description here

  1. Missing { or } due to incorrect indentation

    Mismatched code braces are common to less well-formatted code such as:

    if((!($opt["uniQartz5.8"]!=$this->check58)) or (empty($_POST['poree']))) {if
    ($true) {echo"halp";} elseif((!$z)or%b){excSmthng(False,5.8)}elseif (False){
    

    If your code looks like this, start afresh! Otherwise it's unfixable to you or anyone else. There's no point in showcasing this on the internet to inquire for help.

    You will only be able to fix it, if you can visually follow the nested structure and relation of if/else conditionals and their { code blocks }. Use your IDE to see if they're all paired.

    if (true) {
         if (false) {
                  …
         }
         elseif ($whatever) {
             if ($something2) {
                 …
             } 
             else {
                 …
             }
         }
         else {
             …
         }
         if (false) {    //   a second `if` tree
             …
         }
         else {
             …
         }
    }
    elseif (false) {
        …
    }
    

    Any double } } will not just close a branch, but a previous condition structure. Therefore stick with one coding style; don't mix and match in nested if/else trees.

    Apart from consistency here, it turns out helpful to avoid lengthy conditions too. Use temporary variables or functions to avoid unreadable if-expressions.

  2. IF cannot be used in expressions

    A surprisingly frequent newcomer mistake is trying to use an if statement in an expression, such as a print statement:

                       ⇓
    echo "<a href='" . if ($link == "example.org") { echo …
    

    Which is invalid of course.

    You can use a ternary conditional, but beware of readability impacts.

    echo "<a href='" . ($link ? "http://yes" : "http://no") . "</a>";
    

    Otherwise break such output constructs up: use multiple ifs and echos.
    Better yet, use temporary variables, and place your conditionals before:

    if ($link) { $href = "yes"; } else { $href = "no"; }
    echo "<a href='$href'>Link</a>";
    

    Defining functions or methods for such cases often makes sense too.

    Control blocks don't return "results"

    Now this is less common, but a few coders even try to treat if as if it could return a result:

    $var = if ($x == $y) { "true" };
    

    Which is structurally identical to using if within a string concatenation / expression.

    • But control structures (if / foreach / while) don't have a "result".
    • The literal string "true" would also just be a void statement.

    You'll have to use an assignment in the code block:

    if ($x == $y) { $var = "true"; }
    

    Alternatively, resort to a ?: ternary comparison.

    If in If

    You cannot nest an if within a condition either:

                        ⇓
    if ($x == true and (if $y != false)) { ... }
    

    Which is obviously redundant, because the and (or or) already allows chaining comparisons.

  3. Forgotten ; semicolons

    Once more: Each control block needs to be a statement. If the previous code piece isn't terminated by a semicolon, then that's a guaranteed syntax error:

                    ⇓
    $var = 1 + 2 + 3
    if (true) { … }
    

    Btw, the last line in a {…} code block needs a semicolon too.

  4. Semicolon too early

    Now it's probably wrong to blame a particular coding style, as this pitfall is too easy to overlook:

    if ($x == 5);
    {
        $y = 7;
    }
    else           ←
    {
        $x = -1;    
    }
    

    Which happens more often than you might imagine.

    • When you terminate the if () expression with ; it will execute a void statement. The ; becomes a an empty {} of its own!
    • The {…} block thus is detached from the if, and would always run.
    • So the else no longer had a relation to an open if construct, which is why this would lead to an Unexpected T_ELSE syntax error.

    Which also explains a likewise subtle variation of this syntax error:

    if ($x) { x_is_true(); }; else { something_else(); };
    

    Where the ; after the code block {…} terminates the whole if construct, severing the else branch syntactically.

  5. Not using code blocks

    It's syntactically allowed to omit curly braces {} for code blocks in if/elseif/else branches. Which sadly is a syntax style very common to unversed coders. (Under the false assumption this was quicker to type or read).

    However that's highly likely to trip up the syntax. Sooner or later additional statements will find their way into the if/else branches:

    if (true)
        $x = 5;
    elseif (false)
        $x = 6;
        $y = 7;     ←
    else
        $z = 0;
    

    But to actually use code blocks, you do have to write {} them as such!

    Even seasoned programmers avoid this braceless syntax, or at least understand it as an exceptional exception to the rule.

  6. Else / Elseif in wrong order

    One thing to remind yourself is the conditional order, of course.

    if ($a) { … }
    else { … }
    elseif ($b) { … }
    ↑
    

    You can have as many elseifs as you want, but else has to go last. That's just how it is.

  7. Class declarations

    As mentioned above, you can't have control statements in a class declaration:

    class xyz {
        if (true) {
            function ($var) {}
        }
    

    You either forgot a function definition, or closed one } too early in such cases.

  8. Unexpected T_ELSEIF / T_ELSE

    When mixing PHP and HTML, the closing } for an if/elseif must be in the same PHP block <?php ?> as the next elseif/else. This will generate an error as the closing } for the if needs to be part of the elseif:

    <?php if ($x) { ?>
        html
    <?php } ?>
    <?php elseif ($y) { ?>
        html
    <?php } ?>
    

    The correct form <?php } elseif:

    <?php if ($x) { ?>
        html
    <?php } elseif ($y) { ?>
        html
    <?php } ?>
    

    This is more or less a variation of incorrect indentation - presumably often based on wrong coding intentions.
    You cannot mash other statements inbetween if and elseif/else structural tokens:

    if (true) {
    }
    echo "in between";    ←
    elseif (false) {
    }
    ?> text <?php      ←
    else {
    }
    

    Either can only occur in {…} code blocks, not in between control structure tokens.

    • This wouldn't make sense anyway. It's not like that there was some "undefined" state when PHP jumps between if and else branches.
    • You'll have to make up your mind where print statements belong to / or if they need to be repeated in both branches.

    Nor can you part an if/else between different control structures:

    foreach ($array as $i) {
        if ($i) { … }
    }
    else { … }
    

    There is no syntactic relation between the if and else. The foreach lexical scope ends at }, so there's no point for the if structure to continue.

  9. T_ENDIF

    If an unexpected T_ENDIF is complained about, you're using the alternative syntax style if:elseif:else:endif;. Which you should really think twice about.

    • A common pitfall is confusing the eerily similar : colon for a ; semicolon. (Covered in "Semicolon too early")

    • As indentation is harder to track in template files, the more when using the alternative syntax - it's plausible your endif; does not match any if:.

    • Using } endif; is a doubled if-terminator.

    While an "unexpected $end" is usually the price for a forgotten closing } curly brace.

  10. Assignment vs. comparison

    So, this is not a syntax error, but worth mentioning in this context:

           ⇓
    if ($x = true) { }
    else { do_false(); }
    

    That's not a ==/=== comparison, but an = assignment. This is rather subtle, and will easily lead some users to helplessly edit whole condition blocks. Watch out for unintended assignments first - whenver you experience a logic fault / misbeheviour.


12

意外的T_IS_EQUAL
意外的T_IS_GREATER_OR_EQUAL
意外的T_IS_IDENTICAL
意外的T_IS_NOT_EQUAL
意外的T_IS_NOT_IDENTICAL
意外的T_IS_SMALLER_OR_EQUAL
意外的<
意外的>

比较运算符(例如==>====!=<>!==以及<=<>)大多应该只在表达式中使用,例如if表达式。如果解析器报错,则通常意味着它们的括号不正确匹配或缺失()

  1. 括号分组

    特别是对于带有多个比较的if语句,您必须注意正确计算开放和关闭括号

                            ⇓
    if (($foo < 7) && $bar) > 5 || $baz < 9) { ... }
                          ↑
    

    这里的if条件已经被)终止。

    当您的比较变得足够复杂时,将其拆分为多个和嵌套的if结构通常会有所帮助。

  2. isset()与比较混用

    一个常见的新手陷阱是尝试将isset()empty()与比较混合使用:

  3.                         ⇓
    if (empty($_POST["var"] == 1)) {
    

    甚至更多:

                        ⇓
    if (isset($variable !== "value")) {
    

    对于PHP来说,这是没有意义的,因为issetempty是语言结构,只接受变量名。将它们的结果进行比较也没有意义,因为输出值已经是一个布尔值。

  4. 混淆了>= 大于等于符号与=> 数组运算符

    这两个运算符看起来有些相似,所以有时会混淆:

  5.          ⇓
    if ($var => 5) { ... }
    

    只需记住这个比较运算符被称为“大于等于”,就能正确使用。

    另请参见:PHP中的If语句结构

  6. 没有可比较的对象

    如果两个比较涉及同一个变量名称,则也不能将它们组合在一起:

                     ⇓
    if ($xyz > 5 and < 100)
    

    PHP无法推断您意图再次比较初始变量。表达式通常根据运算符优先级成对组合,因此当看到<时,原始变量只剩下一个布尔结果。

    另请参阅:unexpected T_IS_SMALLER_OR_EQUAL

  7. 比较链

    您不能使用一连串的操作符来比较一个变量:

                      ⇓
     $reult = (5 < $x < 10);
    

    这需要分成两个比较,每个比较都针对$x

    实际上这更像是黑名单表达式(由于等效运算符结合性),在一些C风格的语言中语法上是有效的,但是PHP也不会将其解释成预期的比较链。

  8. 意外的>
    意外的<

    大于号>或小于号<运算符没有自定义的T_XXX记号名称。虽然它们可以被错误地放置,但你更经常看到解析器因为误引用字符串和混淆的HTML而抱怨它们:

  9.                         ⇓
    print "<a href='z">Hello</a>";
                     ↑
    
    这相当于将字符串"<a href='z"与字面常量Hello进行比较,然后再进行另一个<的比较。这至少是PHP的看法。实际原因和语法错误是过早的字符串终止符"

    另外,无法嵌套PHP起始标记:

    <?php echo <?php my_func(); ?>

另请参见:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接