PHP Mechanics And Reflection

Dot Operator And Dot Notation Misconceptions

In PHP, The Dot Is String Concatenation

. in PHP joins two strings. That is its whole job.

PHP example
<?php

declare(strict_types=1);

$first = 'Ada';
$last = 'Lovelace';

echo $first . ' ' . $last . PHP_EOL;   // string concatenation

// Prints:
// Ada Lovelace

So $user.name does not read a name member of $user. PHP evaluates it as "the value $user, concatenated with the constant name" — a string-joining expression that usually is not what you meant and often is not even an error, which is exactly why it is so confusing.

PHP example
<?php

declare(strict_types=1);

$user = 'guest';

// A newcomer writes $user.name expecting member access.
// PHP reads it as: $user . name  ->  'guest' . 'name'
echo $user . 'name' . PHP_EOL;

// Prints:
// guestname

There is no "dot notation" for accessing properties or array elements in PHP. That concept simply does not exist in the language.

PHP's Actual Access Operators

PHP splits what the dot does in other languages across three distinct operators, and choosing the right one is the core skill:

PHP example
<?php

declare(strict_types=1);

$config = ['host' => 'localhost'];          // an array

class Db {
    public string $driver = 'mysql';         // an instance property
    public const VERSION = 8;                // a class constant
}
$db = new Db();

echo $config['host'] . PHP_EOL;   // [] -> array element access
echo $db->driver . PHP_EOL;       // -> -> object property/method access
echo Db::VERSION . PHP_EOL;       // :: -> static/class-level access

// Prints:
// localhost
// mysql
// 8
  • [] accesses an array element by key. (Covered in the array access lesson.)
  • -> accesses a property or method on an object instance. (Covered in the object access lesson.)
  • :: (the scope resolution operator, "double colon" or Paamayim Nekudotayim) accesses class-level things: constants, static properties, and static methods.

The mental translation from a dot-notation language is: figure out what kind of thing you are reaching into — an array, an object instance, or a class itself — and pick [], ->, or :: accordingly. There is no single operator that does all three, and that is the adjustment.

Why This Matters Beyond Syntax

The dot confusion is worth its own lesson because its failures are quiet. Writing . where you meant -> rarely throws a clear "no such operator" error; instead PHP dutifully concatenates, and you get a wrong string, a strange notice about an undefined constant, or a value that is subtly off — bugs that waste far more time than an outright syntax error would. Internalizing "dot means concatenate, and access is [] / -> / ::" removes an entire category of newcomer mistakes.

What To Check

Before moving on, make sure you can:

  • state what . does in PHP (string concatenation) and does not do (member access)
  • explain why $user.name is not an error but is almost never what you want
  • pick between [], ->, and :: based on array vs. instance vs. class
  • name :: as the scope resolution operator for class-level access
  • recognize the quiet, wrong-value failure mode of using . by mistake

What You Should Be Able To Do

After this lesson, you should be able to read and write PHP access expressions without reaching for a dot out of habit, translate "dot notation" from other languages into the correct PHP operator, and recognize the confusing symptoms of having used . where an access operator was meant.

Practice

Practice: Translate Dot Notation To PHP
a) settings.timeout          // settings is an array with a 'timeout' key
b) request.getPath()         // request is an object instance
c) HttpStatus.NOT_FOUND      // NOT_FOUND is a constant on the HttpStatus class
d) user.profile.email        // user and profile are object instances
e) row.data['name']          // row is an object; data is an array property
Show solution
PHP example
<?php

declare(strict_types=1);

// Minimal stand-ins so each answer below actually runs.
$settings = ['timeout' => 30];

class Request {
    public function getPath(): string { return '/albums'; }
}
$request = new Request();

class HttpStatus {
    public const NOT_FOUND = 404;
}

class Profile {
    public string $email = 'ada@example.test';
}
class User {
    public Profile $profile;
    public function __construct() { $this->profile = new Profile(); }
}
$user = new User();

class Row {
    public array $data = ['name' => 'Glasswork'];
}
$row = new Row();

// a) array element by key -> []
$a = $settings['timeout'];

// b) method on an instance -> ->
$b = $request->getPath();

// c) constant on a class -> ::
$c = HttpStatus::NOT_FOUND;

// d) chained instance property access -> -> at each step
$d = $user->profile->email;

// e) mix: instance property (->) then array key ([])
$e = $row->data['name'];

The rule applied each time: ask what kind of thing is being reached into. An array key is always []; a member of an object instance is ->; a member of the class itself (constant, static) is ::. Chains just apply the rule at each hop, and a single expression can mix operators (e) when it crosses from an object to one of its array properties. None of these use a dot, because in PHP the dot would concatenate the operands as strings instead.

Practice: Diagnose A Dot Bug
PHP example
$user = new User();          // has a public string $name = 'Ada';
echo 'Hello ' . $user.name;

Task

Explain exactly what PHP does with $user.name, why the output is wrong, and the fix.

Show solution

The developer meant $user->name (read the name property) but wrote $user.name, and PHP interprets the dot as string concatenation, not member access.

Step by step, PHP evaluates 'Hello ' . $user . name:

  • 'Hello ' is a string.
  • $user is an object; concatenating an object to a string triggers its __toString() if defined, or an error if not — but assume it stringifies to something like User.
  • name is a bareword. PHP treats an unknown bareword as a string constant, and since no constant name is defined, it emits an "Undefined constant" warning (a fatal error in modern PHP) — and that is the source of the mysterious warning. In older PHP it fell back to the literal string 'name'.

So instead of "Hello Ada", the expression concatenates the greeting, the stringified object, and the word "name" — never touching the $name property at all. The property access the developer intended simply never happened.

Fix: use the object access operator.

PHP example
echo 'Hello ' . $user->name;   // Hello Ada

The general lesson: a misplaced dot does not announce itself as "wrong operator." It quietly concatenates and produces a wrong string plus, often, an undefined-constant warning from the bareword — which is the tell-tale signature of a dot that should have been -> or ::.

Practice: Define Dot-Confusion Review Checks

You are reviewing PHP written by developers who mostly work in JavaScript. List the specific dot-related mistakes to watch for and how to spot each.

Show solution
  • A dot immediately after a variable and before a word, like $obj.method or $arr.key. This is almost always a member-access attempt that should be -> or []. Real concatenation usually joins a variable with a string literal or another variable, not a bareword that looks like a property name.
  • "Undefined constant" warnings/errors in logs or CI. As shown in the diagnose exercise, a bareword after a stray dot becomes an undefined constant — this warning is a reliable fingerprint of the mistake.
  • Wrong-but-not-crashing string output — greetings, log lines, or built URLs that contain a stringified object or a stray word. These are dots that concatenated where access was intended.
  • . used to chain, like $a.b.c, expecting property chaining. In PHP that is three-way concatenation; property chaining is $a->b->c.
  • The reverse mistake: -> or [] used where the code genuinely wants to build a string, though this is far rarer.

Tooling helps: static analyzers (PHPStan/Psalm) flag undefined constants and type mismatches that these bugs produce, and a linter catching the undefined-constant class of error will surface most of them automatically. In review, the fastest heuristic is "a dot touching a variable and a bareword" — pause on every one.