Viewed   66 times

How do you access a PHP object's properties?

Also, what is the difference between accessing an object's property with $this->$property1 vs. $this->property1?

When I try to use $this->$property1 I get the following error:

'PHP: Cannot access empty property'.

PHP's documentation on object properties has one comment which mentions this, but the comment doesn't really explain in depth.


  1. $property1 // specific variable
  2. $this->property1 // specific attribute

The general use on classes is without "$" otherwise you are calling a variable called $property1 that could take any value.


class X {
  public $property1 = 'Value 1';
  public $property2 = 'Value 2';
$property1 = 'property2';  //Name of attribute 2
$x_object = new X();
echo $x_object->property1; //Return 'Value 1'
echo $x_object->$property1; //Return 'Value 2'
Monday, October 3, 2022


However what's wrong with using __get and __set that act as dynamic proxies to getName() and setName($val) respectively? Something like:

public function __get($name) { 
    if (method_exists($this, 'get'.$name)) { 
        $method = 'get' . $name; 
        return $this->$method(); 
    } else { 
        throw new OutOfBoundsException('Member is not gettable');

That way you're not stuffing everything into one monster method, but you still can use $foo->bar = 'baz'; syntax with private/protected member variables...

Wednesday, November 2, 2022

The comma is not exclusive of for loops; it is the comma operator.

x = (a, b);

will do first a, then b, then set x to the value of b.

The for syntax is:

for (init; condition; increment)

Which is somewhat (ignoring continue and break for now) equivalent to:

while (condition) {

So your for loop example is (again ignoring continue and break) equivalent to

while (p+=(a&1)*b,a!=1) {

Which acts as if it were (again ignoring continue and break):

while (true) {
    if (a == 1) break;

Two extra details of the for loop which were not in the simplified conversion to a while loop above:

  • If the condition is omitted, it is always true (resulting in an infinite loop unless a break, goto, or something else breaks the loop).
  • A continue acts as if it were a goto to a label just before the increment, unlike a continue in the while loop which would skip the increment.

Also, an important detail about the comma operator: it is a sequence point, like && and || (which is why I can split it in separate statements and keep its meaning intact).

Changes in C99

The C99 standard introduces a couple of nuances not mentioned earlier in this explanation (which is very good for C89/C90).

First, all loops are blocks in their own right. Effectively,

for (...) { ... }

is itself wrapped in a pair of braces

for (...) { ... }

The standard sayeth:

ISO/IEC 9899:1999 §6.8.5 Iteration statements

¶5 An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.

This is also described in the Rationale in terms of the extra set of braces.

Secondly, the init portion in C99 can be a (single) declaration, as in

for (int i = 0; i < sizeof(something); i++) { ... }

Now the 'block wrapped around the loop' comes into its own; it explains why the variable i cannot be accessed outside the loop. You can declare more than one variable, but they must all be of the same type:

for (int i = 0, j = sizeof(something); i < j; i++, j--) { ... }

The standard sayeth:

ISO/IEC 9899:1999 § The for statement

The statement

for ( clause-1 ; expression-2 ; expression-3 ) statement

behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.133)

Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.

133) Thus, clause-1 specifies initialization for the loop, possibly declaring one or more variables for use in the loop; the controlling expression, expression-2, specifies an evaluation made before each iteration, such that execution of the loop continues until the expression compares equal to 0; and expression-3 specifies an operation (such as incrementing) that is performed after each iteration.

Saturday, October 1, 2022

sortBy() takes a closure, allowing you to provide a single value that should be used for sorting comparisons, but you can make it a composite by concatenating several properties together

$posts = $posts->sortBy(function($post) {
    return sprintf('%-12s%s', $post->column1, $post->column2);

If you need the sortBy against multiple columns, you probably need to space pad them to ensure that "ABC" and "DEF" comes after "AB" and "DEF", hence the sprint right padded for each column up to the column's length (at least for all but the last column)

Note that it's generally a lot more efficient if you can use an orderBy in your query so the collection is ready-sorted on retrieval from the database

Saturday, September 17, 2022

For Option E, by using the "final" modifier you could prevent a whole new AttributeAtom being swapped in, whilst still allowing getting/setting:

public final AttributeAtom<String> myAttribute = new FilePathAttributeAtom("myAttribtue");

Then the following will be allowed:


But the thing you're worried about won't be:

myAtom.myAttribute = completelyDifferentAttribute
Wednesday, October 12, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :