diff --git a/language/control-structures.xml b/language/control-structures.xml index 3ef4d1b7f3..8adff8a756 100644 --- a/language/control-structures.xml +++ b/language/control-structures.xml @@ -28,6 +28,7 @@ array echo eval + print diff --git a/reference/strings/functions/echo.xml b/reference/strings/functions/echo.xml index 3f136d3951..12c3479026 100644 --- a/reference/strings/functions/echo.xml +++ b/reference/strings/functions/echo.xml @@ -10,27 +10,23 @@ &reftitle.description; voidecho - stringarg - stringargs + stringexpressions - Outputs all parameters. No additional newline is appended. + Outputs one or more expressions, with no additional newlines or spaces. - echo is not actually a function (it is a - language construct), so you are not required to use parentheses - with it. echo (unlike some other language - constructs) does not behave like a function, so it cannot - always be used in the context of a function. Additionally, if you want to - pass more than one parameter to echo, the parameters - must not be enclosed within parentheses. + echo is not a function but a language language construct. + Its arguments are a list of expressions following the echo + keyword, separated by commas, and not delimited by parentheses. + Unlike some other language constructs, echo does not have + any return value, so it cannot be used in the context of an expression. echo also has a shortcut syntax, where you can - immediately follow the opening tag with an equals sign. Prior to PHP 5.4.0, - this short syntax only works with the - short_open_tag configuration - setting enabled. + immediately follow the opening tag with an equals sign. This syntax is available + even with the short_open_tag configuration + setting disabled. foo. - The major differences to print are that - echo accepts an argument list and doesn't have a return value. + The major differences to print are that + echo accepts multiple arguments and doesn't have a return value. @@ -50,17 +46,13 @@ I have foo. - arg - - - The parameter to output. - - - - - args + expressions + One or more string expressions to output, separated by commas. + Non-string values will be coerced to strings, even when + the + strict_types directive is enabled. @@ -83,22 +75,45 @@ I have foo. ]]> @@ -109,31 +124,82 @@ echo $some_var ? 'true': 'false'; // changing the statement around &reftitle.notes; ¬e.language-construct; + + + Using with parentheses + + Surrounding a single argument to echo with parentheses will not + raise a syntax error, and produces syntax which looks like a normal + function call. However, this can be misleading, because the parentheses are actually + part of the expression being output, not part of the echo + syntax itself. + + + + + <programlisting role="php"> + <![CDATA[ +<?php +echo "hello"; +// outputs "hello" + +echo("hello"); +// also outputs "hello", because ("hello") is a valid expression + +echo(1 + 2) * 3; +// outputs "9"; the parentheses cause 1+2 to be evaluated first, then 3*3 +// the echo statement sees the whole expression as one argument + +echo "hello", " world"; +// outputs "hello world" + +echo("hello"), (" world"); +// outputs "hello world"; the parentheses are part of each expression + +echo("hello", " world"); +// Throws a Parse Error because ("hello", " world") is not a valid expression +?> +]]> + </programlisting> + </example> + </para> + </note> + <tip> <para> - A benefit to passing in multiple arguments over using concatenation in - <function>echo</function> regards the precedence of the period operator in - PHP. If multiple arguments are passed in, then parentheses will not be - required to enforce precedence: + Passing multiple arguments to <literal>echo</literal> can avoid + complications arising from the precedence of the concatenation operator in + PHP. For instance, the concatenation operator has higher precedence than + the ternary operator, and prior to PHP 8.0.0 had the same precedence as addition + and subtraction: </para> <programlisting role="php"> -<![CDATA[ + <![CDATA[ <?php -echo "Sum: ", 1 + 2; -echo "Hello ", isset($name) ? $name : "John Doe", "!"; +// Below, the expression 'Hello ' . isset($name) is evaluated first, +// and is always true, so the argument to echo is always $name +echo 'Hello ' . isset($name) ? $name : 'John Doe' . '!'; + +// The intended behaviour requires additional parentheses +echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!'; + +// In PHP prior to 8.0.0, the below outputs "2", rather than "Sum: 3" +echo 'Sum: ' . 1 + 2; + +// Again, adding parentheses ensures the intended order of evaluation +echo 'Sum: ' . (1 + 2); ]]> </programlisting> - <para> - With concatenation, the period operator has the same precedence as - the addition operator, and higher precedence than the ternary operator, so parentheses must be used for the - correct behaviour: + If multiple arguments are passed in, then parentheses will not be + required to enforce precedence, because each expression is separate: </para> <programlisting role="php"> <![CDATA[ <?php -echo 'Sum: ' . (1 + 2); -echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!'; +echo "Hello ", isset($name) ? $name : "John Doe", "!"; + +echo "Sum: ", 1 + 2; ]]> </programlisting> </tip> @@ -146,7 +212,7 @@ echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!'; <member><function>print</function></member> <member><function>printf</function></member> <member><function>flush</function></member> - <member><link linkend="language.types.string.syntax.heredoc">Heredoc syntax</link></member> + <member><link linkend="language.types.string">Ways to specify literal strings</link></member> </simplelist> </para> </refsect1> diff --git a/reference/strings/functions/print.xml b/reference/strings/functions/print.xml index 8247cfc8b0..6512037391 100644 --- a/reference/strings/functions/print.xml +++ b/reference/strings/functions/print.xml @@ -10,19 +10,20 @@ &reftitle.description; <methodsynopsis> <type>int</type><methodname>print</methodname> - <methodparam><type>string</type><parameter>arg</parameter></methodparam> + <methodparam><type>string</type><parameter>expression</parameter></methodparam> </methodsynopsis> <para> - Outputs <parameter>arg</parameter>. + Outputs <parameter>expression</parameter>. </para> <para> - <literal>print</literal> is not actually a real function (it is a - language construct) so you are not required to use parentheses - with its argument list. + <literal>print</literal> is not a function but a language language construct. + Its argument is the expression following the <literal>print</literal> keyword, + and is not delimited by parentheses. </para> <para> - The major differences to <literal>echo</literal> are that - <literal>print</literal> only accepts a single argument and always returns 1. + The major differences to <function>echo</function> are that + <literal>print</literal> only accepts a single argument and always returns + <literal>1</literal>. </para> </refsect1> @@ -31,10 +32,12 @@ <para> <variablelist> <varlistentry> - <term><parameter>arg</parameter></term> + <term><parameter>expression</parameter></term> <listitem> <para> - The input data. + The expression to be output. Non-string values will be coerced to strings, + even when <link linkend="language.types.declarations.strict">the + <literal>strict_types</literal> directive</link> is enabled. </para> </listitem> </varlistentry> @@ -57,41 +60,36 @@ <programlisting role="php"> <![CDATA[ <?php -print("Hello World"); +print "print does not require parentheses."; -print "print() also works without parentheses."; +// No newline or space is added; the below outputs "helloworld" all on one line +print "hello"; +print "world"; -print "This spans +print "This string spans multiple lines. The newlines will be output as well"; -print "This spans\nmultiple lines. The newlines will be\noutput as well."; +print "This string spans\nmultiple lines. The newlines will be\noutput as well."; -print "escaping characters is done \"Like this\"."; +// The argument can be any expression which produces a string +$foo = "example"; +print "foo is $foo"; // foo is example -// You can use variables inside a print statement -$foo = "foobar"; -$bar = "barbaz"; +$fruits = ["lemon", "orange", "banana"]; +print implode(" and ", $fruits); // lemon and orange and banana -print "foo is $foo"; // foo is foobar +// Non-string expressions are coerced to string, even if declare(strict_types=1) is used +print 6 * 7; // 42 -// You can also use arrays -$bar = array("value" => "foo"); +// Because print has a return value, it can be used in expressions +// The following outputs "hello world" +if ( print "hello" ) { + echo " world"; +} -print "this is {$bar['value']} !"; // this is foo ! - -// Using single quotes will print the variable name, not the value -print 'foo is $foo'; // foo is $foo - -// If you are not using any other characters, you can just print variables -print $foo; // foobar - -print <<<END -This uses the "here document" syntax to output -multiple lines with $variable interpolation. Note -that the here document terminator must appear on a -line with just a semicolon no extra whitespace! -END; +// The following outputs "true" +( 1 === 1 ) ? print 'true' : print 'false'; ?> ]]> </programlisting> @@ -101,6 +99,85 @@ END; <refsect1 role="notes"> &reftitle.notes; + + <note> + <title>Using with parentheses + + Surrounding the argument to print with parentheses will not + raise a syntax error, and produces syntax which looks like a normal + function call. However, this can be misleading, because the parentheses are actually + part of the expression being output, not part of the print + syntax itself. + + + + + <programlisting role="php"> +<![CDATA[ +<?php +print "hello"; +// outputs "hello" + +print("hello"); +// also outputs "hello", because ("hello") is a valid expression + +print(1 + 2) * 3; +// outputs "9"; the parentheses cause 1+2 to be evaluated first, then 3*3 +// the print statement sees the whole expression as one argument + +if ( print("hello") && false ) { + print " - inside if"; +} +else { + print " - inside if"; +} +// outputs "0 is the answer" +// the expression ("not the answer") && false is first evaluated, giving false +// this is coerced to the empty string "" and printed +// the print construct then returns 1, so code in the if block is run +?> +]]> + </programlisting> + </example> + </para> + + <para> + When using <literal>print</literal> in a larger expression, placing both the + keyword and its argument in parentheses may be necessary to give the intended + result: + </para> + + <para> + <example> + <title/> + <programlisting role="php"> +<![CDATA[ +<?php +if ( (print "hello") && false ) { + print " - inside if"; +} +else { + print " - inside else"; +} +// outputs "hello - inside else" +// unlike the previous example, the expression (print "hello") is evaluated first +// after outputting "hello", print returns 1 +// since 1 && false is false, code in the else block is run + +print "hello " && print "world"; +// outputs "world1"; print "world" is evaluated first, +// then the expression "hello " && 1 is passed to the left-hand print + +(print "hello ") && (print "world"); +// outputs "hello world"; the parentheses force the print expressions +// to be evaluated before the && +?> +]]> + </programlisting> + </example> + </para> + </note> + ¬e.language-construct; </refsect1> @@ -111,7 +188,7 @@ END; <member><function>echo</function></member> <member><function>printf</function></member> <member><function>flush</function></member> - <member><link linkend="language.types.string.syntax.heredoc">Heredoc syntax</link></member> + <member><link linkend="language.types.string">Ways to specify literal strings</link></member> </simplelist> </para> </refsect1>