What is the "->" PHP operator called? [closed] - php

Closed. This question is opinion-based. It is not currently accepting answers.
Closed 5 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What do you call this arrow looking -> operator found in PHP?
It's either a minus sign, dash or hyphen followed by a greater than sign (or right chevron).
How do you pronounce it when reading code out loud?

The official name is "object operator" - T_OBJECT_OPERATOR.

I call it "dart"; as in $Foo->bar() : "Foo dart bar"
Since many languages use "dot" as in Foo.bar(); I wanted a one-syllable word to use. "Arrow" is just too long-winded! ;)
Since PHP uses . "dot" for concatenation (why?) I can't safely say "dot" -- it could confuse.
Discussing with a co-worker a while back, we decided on "dart" as a word similar enough to "dot" to flow comfortably, but distinct enough (at least when we say it) to not be mistaken for a concatenating "dot".

When reading PHP code aloud, I don't pronounce the "->" operator. For $db->prepare($query); I mostly say "Db [short pause] prepare query." So I guess I speak it like a comma in a regular sentence.
The same goes for the Paamayim Nekudotayim ("::").

When reading the code to myself, I think of it like a "possessive thing".
For example:
x->value = y->value
would read "x's value equals y's value"

Most often, I use some variation on #Tor Valamo's method ("the B method of A" or "A's B method"), but I sometimes say "dot". E.g. "call A dot B()".

Property operator.
When reading $a->b() or $a->b loud I just say "call b on the $a obj" or "get b from/in/of $a"

I personally like to be verbose in expressing my code verbally.
e.g.:
$foo = new Foo();
echo $foo->bar
would read as such:
echo(/print) the bar property of object foo.
It's verbose and more time consuming, but I find if there is a reason for me to be expressing my code verbally, then I probably need to be clear as to what I'm communicating exactly.

Harkening back to the Cobol 'in' where you would say "Move 5 to b in a." Most languages today qualify things the other direction.
Yet I would still read $a->b(); as "Call b in a".

$a->b
I call as "param b of $a".
$a->b()
I call as "function b of $a".

The single arrow can easily be referred verbally as what it means for PHP OOP: Member. So, for $a->var you would say "Object a's member var".
When reading code aloud, it does help to read ahead (lookahead reference, sorry), and know what you may actually be referring to. For instance, let's have the following bit of code:
<?php
Class MyClass {
$foo = 0;
public function bar() {
return $this->foo;
}
}
$myobject = new MyClass();
$myobject->bar();
?>
So, if I were to read aloud this code block as a demonstration of code, I would say this:
"Define Class 'MyClass', open-brace. Variable 'foo' equals zero, terminate line. Define public function 'bar' open-close parentheses, open-brace. Return member variable 'foo' of object 'this', terminate line. Close-brace, close-brace. Instantiate new instance of 'MyClass' (no arguments) as variable object 'myobject', terminate line. Call member method 'bar' of object 'myobject', terminate line."
However, if I were reading the code aloud for other students or programmers to copy without a visual, then I would say:
"PHP open tag (full), newline, indent, Class MyClass open-brace, newline. Indent, ['dollar-sign' | 'Object-marker'] foo equals 0, semicolon, newline, newline. public function bar open-close parentheses, open-brace, newline. Indent, return ['dollar-sign' | 'Object-marker'] this arrow foo, semicolon, newline. Reverse-indent, close-brace, newline, reverse-indent, close-brace, newline, newline. ['dollar-sign' | 'Object-marker'] myobject equals new MyClass open-close parentheses, semicolon, newline. ['dollar-sign' | 'Object-marker'] myobject arrow bar open-close parentheses, semicolon, newline. Reverse-indent, PHP close tag."
Where you see ['dollar-sign' | 'Object-marker'], just choose whichever you tend to speak for '$', I switch between the two frequently, just depends on my audience.
So, to sum it up, in PHP, -> refers to a member of an object, be it either a variable, another object, or a method.

The senior PHP developer where I work says "arrow".
$A->B;
When he's telling me to type the above, he'll say, "Dollar A arrow B" or for
$A->B();
"Dollar A arrow B parens."

I would do it like this:
//Instantiated object variable with the name mono call property name
$mono->name;
//Instantiated object variable with the name mono call method ship
$mono->ship();
In my book (PHP Master by Lorna Mitchell) it's called the object operator.

user187291 has answered the non-subjective question, as for the subjective one, I say "sub". For example, I would pronounce $x->y as "x sub y" - "sub" in this context is short for "subscript". This is more appropriate for array notation; $x['y'] I also pronounce "x sub y". Typically when reading code out loud, I am using my words to identify a line the other developer can see, so the ambiguity has yet to become a problem. I believe the cause is that I view structs/objects and arrays as "collections", and elements thereof are subscripted as in mathematical notation.

Japanese has a convenient particle for this, "no" (の). It is the possessive particle, meaning roughly "relating to the preceding term".
"Fred の badger" means "Fred's badger".
Which is a long way round of saying that at least mentally, and also amongst those who understand Japanese, I tend to differentiate them by reading them as:
$A->B(); // "Call $A's B."
C::D(); // "Call C の D."
But reading both as a possessive "'s" works too, for non-Japanese speakers. You can also flip them and use "of", so "D of C"... but that's kinda awkward, and hard to do it you're reading rapidly because it breaks your linear flow.
If I were dictating, though, perhaps when pair coding and suggesting what to type, I'd refer to the specific characters as "dash-greater-than arrow" and "double-colon" (if i know the person I'm talking to is a PHPophile, I might call that a "paamayim nekudotayim double-colon" the first time, partly because it's a cool in-joke, partly to prevent them from "correcting" me).

Object. So $a->$b->$c would be 'A object B object c'.

Related

Avoid a "PHP Strict standards" warning with parentheses? [duplicate]

It was noted in another question that wrapping the result of a PHP function call in parentheses can somehow convert the result into a fully-fledged expression, such that the following works:
<?php
error_reporting(E_ALL | E_STRICT);
function get_array() {
return array();
}
function foo() {
// return reset(get_array());
// ^ error: "Only variables should be passed by reference"
return reset((get_array()));
// ^ OK
}
foo();
I'm trying to find anything in the documentation to explicitly and unambiguously explain what is happening here. Unlike in C++, I don't know enough about the PHP grammar and its treatment of statements/expressions to derive it myself.
Is there anything hidden in the documentation regarding this behaviour? If not, can somebody else explain it without resorting to supposition?
Update
I first found this EBNF purporting to represent the PHP grammar, and tried to decode my scripts myself, but eventually gave up.
Then, using phc to generate a .dot file of the two foo() variants, I produced AST images for both scripts using the following commands:
$ yum install phc graphviz
$ phc --dump-ast-dot test1.php > test1.dot
$ dot -Tpng test1.dot > test1.png
$ phc --dump-ast-dot test2.php > test2.dot
$ dot -Tpng test2.dot > test2.png
In both cases the result was exactly the same:
This behavior could be classified as bug, so you should definitely not rely on it.
The (simplified) conditions for the message not to be thrown on a function call are as follows (see the definition of the opcode ZEND_SEND_VAR_NO_REF):
the argument is not a function call (or if it is, it returns by reference), and
the argument is either a reference or it has reference count 1 (if it has reference count 1, it's turned into a reference).
Let's analyze these in more detail.
First point is true (not a function call)
Due to the additional parentheses, PHP no longer detects that the argument is a function call.
When parsing a non empty function argument list there are three possibilities for PHP:
An expr_without_variable
A variable
(A & followed by a variable, for the removed call-time pass by reference feature)
When writing just get_array() PHP sees this as a variable.
(get_array()) on the other hand does not qualify as a variable. It is an expr_without_variable.
This ultimately affects the way the code compiles, namely the extended value of the opcode SEND_VAR_NO_REF will no longer include the flag ZEND_ARG_SEND_FUNCTION, which is the way the function call is detected in the opcode implementation.
Second point is true (the reference count is 1)
At several points, the Zend Engine allows non-references with reference count 1 where references are expected. These details should not be exposed to the user, but unfortunately they are here.
In your example you're returning an array that's not referenced from anywhere else. If it were, you would still get the message, i.e. this second point would not be true.
So the following very similar example does not work:
<?php
$a = array();
function get_array() {
return $GLOBALS['a'];
}
return reset((get_array()));
A) To understand what's happening here, one needs to understand PHP's handling of values/variables and references (PDF, 1.2MB). As stated throughout the documentation: "references are not pointers"; and you can only return variables by reference from a function - nothing else.
In my opinion, that means, any function in PHP will return a reference. But some functions (built in PHP) require values/variables as arguments. Now, if you are nesting function-calls, the inner one returns a reference, while the outer one expects a value. This leads to the 'famous' E_STRICT-error "Only variables should be passed by reference".
$fileName = 'example.txt';
$fileExtension = array_pop(explode('.', $fileName));
// will result in Error 2048: Only variables should be passed by reference in…
B) I found a line in the PHP-syntax description linked in the question.
expr_without_variable = "(" expr ")"
In combination with this sentence from the documentation: "In PHP, almost anything you write is an expression. The simplest yet most accurate way to define an expression is 'anything that has a value'.", this leads me to the conclusion that even (5) is an expression in PHP, which evaluates to an integer with the value 5.
(As $a = 5 is not only an assignment but also an expression, which evalutes to 5.)
Conclusion
If you pass a reference to the expression (...), this expression will return a value, which then may be passed as argument to the outer function. If that (my line of thought) is true, the following two lines should work equivalently:
// what I've used over years: (spaces only added for readability)
$fileExtension = array_pop( ( explode('.', $fileName) ) );
// vs
$fileExtension = array_pop( $tmp = explode('.', $fileName) );
See also PHP 5.0.5: Fatal error: Only variables can be passed by reference; 13.09.2005

How can "[" be an operator in the PHP language specification?

On the http://php.net/manual/en/language.operators.precedence.php webpage, the second highest precedence level contains a left-associative operator called [.
I don't understand that. Is it the [ used to access/modify array entries, as in $myArray[23] ? I cannot imagine any code snippet where we would need to know the "precedence" of it wrt other operators, or where the "associativity" of [ would be useful.
This is a very valid question.
1. Precedence in between [...]
First there is never an ambiguity to what PHP should evaluate first when looking at the
right side of the [, since the bracket requires a closing one to go with it, and so
every operator in between has precedence over the opening bracket.
Example:
$a[1+2]
The + has precedence, i.e. first 1+2 has to be evaluated before PHP can determine which
element to retrieve from $a.
But the operator precedence list is not about this.
2. Associativity
Secondly there is an order of evaluating consecutive pairs of [], like here:
$b[1][2]
PHP will first evaluate $b[1] and then apply [2] to that. This is left-to-right
evaluation and is what is intended with left associativity.
But the question at hand is not so much about associativity, but about precedence with regards to other operators.
3. Precedence over operators on the left side
The list states that clone and new operators have precedence over [, and this is not easy to test.
First of all, most of the constructs where you would combine new with square brackets are considered invalid
syntax. For example, both of these statements:
$a = new myClass()[0];
$a = new myClass[0];
will give a parsing error:
syntax error, unexpected '['
PHP requires you to add parentheses to make the syntax valid. So there is no way we can test
the precedence rules like this.
But there is another way, by using a variable containing a class name:
$a = new $test[0];
This is valid syntax, but now the challenge is to make a class that creates something
that acts like an array.
This is not trivial to do, as an object property is referenced like this: obj->prop, not
like obj["prop"]. One can however use the ArrayObject class which can deal with square brackets. The idea is to extend this class and redefine the offsetGet method to make sure a freshly made object of that class has array elements to return.
To make objects printable, I ended up using the magical method __toString, which is executed when an object needs to be cast to a string.
So I came up with this set-up, defining two similar classes:
class T extends ArrayObject {
public function __toString() {
return "I am a T object";
}
public function offsetGet ($offset) {
return "I am a T object's array element";
}
}
class TestClass extends ArrayObject {
public function __toString() {
return "I am a TestClass object";
}
public function offsetGet ($offset) {
return "I am a TestClass object's array element";
}
}
$test = "TestClass";
With this set-up we can test a few things.
Test 1
echo new $test;
This statement creates a new TestClass instance, which then needs to be converted to
string, so the __toString method is called on that new instance, which returns:
I am a TestClass object
This is as expected.
Test 2
echo (new $test)[0];
Here we start with the same actions, as the parentheses force the new operation to be executed first. This time PHP does not convert the created object to string, but requests array element 0 from it. This request is answered by the offsetGet method, and so the above statement outputs:
I am a TestClass object's array element
Test 3
echo new ($test[0]);
The idea is to force the opposite order of execution. Sadly enough, PHP does not allow this syntax, so will have to break the statement into two in order to get the intended evaluation order:
$name = $test[0];
echo new $name;
So now the [ is executed first, taking the first character of the value of
$test, i.e. "T", and then new is applied to that. That's why I
defined also a T class. The echo calls __toString on that instance, which yields:
I am a T object
Now comes the final test to see which is the order when no parentheses are present:
Test 4
echo new $test[0];
This is valid syntax, and...
4. Conclusion
The output is:
I am a T object
So in fact, PHP applied the [ before the new operator, despite what is stated in the
operator precedence table!
5. Comparing clone with new
The clone operator has similar behaviour in combination with [. Strangely enough, clone and new are not completely equal in terms of syntax rules. Repeating test 2 with clone:
echo (clone $test)[0];
yields a parsing error:
syntax error, unexpected '['
But test 4 repeated with clone shows that [ has precedence over it.
#bishop informed that this reproduces the long standing documentation bug #61513: "clone operator precedence is wrong".
It just means the array variable (left associativity - $first) will be evaluated before the array key (right associativity - $second)
$first[$second]
This have lot of sense when array has multiple dimensions
$first[$second][$third][$fourth]
In PHP you can initialize empty arrays with [] so in order to know how to define an array the precedence of the next character defines on how to initialize the array.
Since arrays are part of the syntax structure, it is done before any math, it simply has a higher precedence than other calculative operators for that reason.
var_dump([5, 6, 7] + [1, 2, 3, 4]); # 5674 - The array's must be known before applying the operator
However in all honesty I don't really understand the question. In most programming languages the [ and the ] are associated with arrays which is part of the base syntax that always have a high priority (if not the highest)

Assign expression to the arc and execute it

I need to implement the following thing in my web-application. I know my solution is incorrect, but I put the code jsut to demonstrate the idea.
There is a class 'arc'. I need to be able to assign ANY expression to this arc (e.g. a+b+c,a-c,if-then). Once expression is assigned, I'd like to be able to execute it with some randomly taken variables. Is it possible to implement such functionality in web-applications? Maybe, I should use some plug-in like MathPL? Or maybe there is an absolutely different approach to tackle such kind of problems?
class arc {
var $arcexpression;
function setExpression($arcexpression) {
$this->arcexpression = $arcexpression;
}
function getExpression() {
return $this->arcexpression;
}
}
$arc = new arc();
$arc->setExpression("if a>b then return a else return b");
$result = $arc->execute(a,b); // the function 'execute' should be somehow described in 'arc'
You don't need to implement a whole language for this. I would start by limiting what can be done, for example, limit your expressions to arithmetic operators (+, -, *, /), parentheses and if-then operator. You'll need to enforce some sort of syntax for if-then to make it easier, possibly, the same as php's operator ?:. After that you need to build a parser for this grammar only: to parse a given expression into a tree. For example, expression `a + b * c' would parse into something like this:
+
/ \
a *
/ \
b c
After that you'll just have to evaluate such expressions. For example, by passing an array into your evaluate function of type { a => 1, b => 2, c => 3 }, you'll get 7 out of it.
The idea of the parse is the following:
Start from position 1 in the string - and call a recursive function to parse data from that position. In the function, start reading from the specified position.
If you read an opening parenthesis, call itself recursively
If you encounter a closing parenthesis or end-of-string, return the root node
Read the first identifier (or recursively inside parentheses)
Read the arithmetic sign
Read the second identifier (or recursively inside parentheses)
If the sign is * or /, then create the node with the sign in it and two operands as children and attach that node as the corresponding (left or right) child of the previous operator.
If the sign is + or -, then find create the node with the sign in it, one of the children being one of the operands and the second node being the root of the subtree with * and / at the root (or the second operand, if it's a simple operation).
Getting pure arithmetic, with parentheses, working is easy; if-then is a bit more tricky, but still not too bad. About 10 years ago I had to implement something like this in Java. It took me about 3 days to get everything sorted and was in total about 500 lines of code in 1 class, not counting javadoc. I suspect in PHP it will be less code, due to sheer simplicity of PHP syntax and type conversions.
It may sound complicated, but, in reality, it's much easier than it seems once you start doing it. I remember very well a university assignment to do something similar as part of the algorithms class, 17-18 years ago.

PHP array syntax/operator?

When writing the syntax for an associative array in PHP we do the following
$a = array('foo' => 'bar');
I am curious of the relationship of the => syntax, or possibly operator. Does this relate to some kind of reference used in the hash table in ZE, or some kind of subsequent right shift or reference used in C? I guess I am just wondering the true underlying purpose of this syntax, how it relates to ZE and/or php extensions used to handle arrays, how it possibly relates to the written function in C before compiled, or If I just have no idea what I am talking about :)
The => symbol a.k.a. T_DOUBLE_ARROW is just a parser token like class, || or ::.
See: The list of php parser tokens
It's nothing special apart from that fact that "it looks like an arrow" and it is used for "array stuff".
Of course the exact usage is more complicated than that but "array stuff" is the short inaccurate description that should do it.
It's used to represent key => (points to) value
The answer to that is no simpler than "It looks like an arrow".
It's not exactly the assignment operator per say because that would mean a variable-like assignment (like for the array itself). This is an array-internals specific assignment operator.
Webdevelopers are cool like that :P

Why don't PHP attributes allow functions?

I'm pretty new to PHP, but I've been programming in similar languages for years. I was flummoxed by the following:
class Foo {
public $path = array(
realpath(".")
);
}
It produced a syntax error: Parse error: syntax error, unexpected '(', expecting ')' in test.php on line 5 which is the realpath call.
But this works fine:
$path = array(
realpath(".")
);
After banging my head against this for a while, I was told you can't call functions in an attribute default; you have to do it in __construct. My question is: why?! Is this a "feature" or sloppy implementation? What's the rationale?
The compiler code suggests that this is by design, though I don't know what the official reasoning behind that is. I'm also not sure how much effort it would take to reliably implement this functionality, but there are definitely some limitations in the way that things are currently done.
Though my knowledge of the PHP compiler isn't extensive, I'm going try and illustrate what I believe goes on so that you can see where there is an issue. Your code sample makes a good candidate for this process, so we'll be using that:
class Foo {
public $path = array(
realpath(".")
);
}
As you're well aware, this causes a syntax error. This is a result of the PHP grammar, which makes the following relevant definition:
class_variable_declaration:
//...
| T_VARIABLE '=' static_scalar //...
;
So, when defining the values of variables such as $path, the expected value must match the definition of a static scalar. Unsurprisingly, this is somewhat of a misnomer given that the definition of a static scalar also includes array types whose values are also static scalars:
static_scalar: /* compile-time evaluated scalars */
//...
| T_ARRAY '(' static_array_pair_list ')' // ...
//...
;
Let's assume for a second that the grammar was different, and the noted line in the class variable delcaration rule looked something more like the following which would match your code sample (despite breaking otherwise valid assignments):
class_variable_declaration:
//...
| T_VARIABLE '=' T_ARRAY '(' array_pair_list ')' // ...
;
After recompiling PHP, the sample script would no longer fail with that syntax error. Instead, it would fail with the compile time error "Invalid binding type". Since the code is now valid based on the grammar, this indicates that there actually is something specific in the design of the compiler that's causing trouble. To figure out what that is, let's revert to the original grammar for a moment and imagine that the code sample had a valid assignment of $path = array( 2 );.
Using the grammar as a guide, it's possible to walk through the actions invoked in the compiler code when parsing this code sample. I've left some less important parts out, but the process looks something like this:
// ...
// Begins the class declaration
zend_do_begin_class_declaration(znode, "Foo", znode);
// Set some modifiers on the current znode...
// ...
// Create the array
array_init(znode);
// Add the value we specified
zend_do_add_static_array_element(znode, NULL, 2);
// Declare the property as a member of the class
zend_do_declare_property('$path', znode);
// End the class declaration
zend_do_end_class_declaration(znode, "Foo");
// ...
zend_do_early_binding();
// ...
zend_do_end_compilation();
While the compiler does a lot in these various methods, it's important to note a few things.
A call to zend_do_begin_class_declaration() results in a call to get_next_op(). This means that it adds a new opcode to the current opcode array.
array_init() and zend_do_add_static_array_element() do not generate new opcodes. Instead, the array is immediately created and added to the current class' properties table. Method declarations work in a similar way, via a special case in zend_do_begin_function_declaration().
zend_do_early_binding() consumes the last opcode on the current opcode array, checking for one of the following types before setting it to a NOP:
ZEND_DECLARE_FUNCTION
ZEND_DECLARE_CLASS
ZEND_DECLARE_INHERITED_CLASS
ZEND_VERIFY_ABSTRACT_CLASS
ZEND_ADD_INTERFACE
Note that in the last case, if the opcode type is not one of the expected types, an error is thrown – The "Invalid binding type" error. From this, we can tell that allowing the non-static values to be assigned somehow causes the last opcode to be something other than expected. So, what happens when we use a non-static array with the modified grammar?
Instead of calling array_init(), the compiler prepares the arguments and calls zend_do_init_array(). This in turn calls get_next_op() and adds a new INIT_ARRAY opcode, producing something like the following:
DECLARE_CLASS 'Foo'
SEND_VAL '.'
DO_FCALL 'realpath'
INIT_ARRAY
Herein lies the root of the problem. By adding these opcodes, zend_do_early_binding() gets an unexpected input and throws an exception. As the process of early binding class and function definitions seems fairly integral to the PHP compilation process, it can't just be ignored (though the DECLARE_CLASS production/consumption is kind of messy). Likewise, it's not practical to try and evaluate these additional opcodes inline (you can't be sure that a given function or class has been resolved yet), so there's no way to avoid generating the opcodes.
A potential solution would be to build a new opcode array that was scoped to the class variable declaration, similar to how method definitions are handled. The problem with doing that is deciding when to evaluate such a run-once sequence. Would it be done when the file containing the class is loaded, when the property is first accessed, or when an object of that type is constructed?
As you've pointed out, other dynamic languages have found a way to handle this scenario, so it's not impossible to make that decision and get it to work. From what I can tell though, doing so in the case of PHP wouldn't be a one-line fix, and the language designers seem to have decided that it wasn't something worth including at this point.
My question is: why?! Is this a "feature" or sloppy implementation?
I'd say it's definitely a feature. A class definition is a code blueprint, and not supposed to execute code at the time of is definition. It would break the object's abstraction and encapsulation.
However, this is only my view. I can't say for sure what idea the developers had when defining this.
You can probably achieve something similar like this:
class Foo
{
public $path = __DIR__;
}
IIRC __DIR__ needs php 5.3+, __FILE__ has been around longer
It's a sloppy parser implementation. I don't have the correct terminology to describe it (I think the term "beta reduction" fits in somehow...), but the PHP language parser is more complex and more complicated than it needs to be, and so all sorts of special-casing is required for different language constructs.
My guess would be that you won't be able to have a correct stack trace if the error does not occur on an executable line... Since there can't be any error with initializing values with constants, there's no problem with that, but function can throw exceptions/errors and need to be called within an executable line, and not a declarative one.

Categories