Originally published on php2rust.dev — part of the PHP to Rust course. View this lesson on the original site.

Shadowing in Rust lets you use let again with the same name. Each time you do, you get a new binding. From that point on in the same scope, the name refers only to the newest binding, you can’t use that name to reach the older value anymore (the compiler treats the old binding as shadowed: same spelling, but it’s “behind” the new one). The new binding can also have a different type. PHP does not work this way: reassignment updates the same variable in place.

Rust

fn main() {
    let x = 5;
    let x = x + 1;        // Shadows: new x = 6
    let x = x * 2;        // Shadows again: new x = 12
    println!("x is {}", x);  // 12

    // Shadowing allows changing type
    let count = "five";
    let count = count.len();  // count is now usize (4)
    println!("count is {}", count);
}

Each let x creates a new variable. The name x now means the new binding; the earlier x values are not gone instantly in every sense (Rust may still drop them in order as the block ends), but you have no way to refer to them by x after the next shadowing line. That’s what “hidden” means: hidden from this name, not necessarily erased from memory the same second.

Can you access the old binding again? Not by the same name. Rust does not let you “unwrap” shadowing. If you need both values, use two names (e.g. let x = 5; let y = x + 1;) or restructure so you only shadow when you no longer need the previous meaning (common pattern: let s = "42"; let s: u32 = s.parse().unwrap();).

If you already shadowed and didn’t save the old value in another variable, there’s no way to “look up” the shadowed binding again, the language doesn’t expose it.

PHP

PHP does not support shadowing. Reassignment changes the value of the same variable, and you cannot change its type in a straightforward way:

<?php
$x = 5;
$x = $x + 1;    // Same variable, new value (6)
$x = $x * 2;    // Same variable, new value (12)
echo "x is $x\n";  // 12

$count = "five";
$count = strlen($count);  // Same variable, now holds int 5
echo "count is $count\n";  // 5

PHP’s dynamic typing allows the type to change, but it’s a single variable being overwritten, not a new binding.

Comparison

  • Rust: Shadowing creates a new binding with the same name; the old binding is no longer reachable under that name (only the latest let wins). You can change type when shadowing.
  • PHP: Reassignment overwrites the same variable; type can change due to dynamic typing.

Rust uses shadowing for transformations (e.g. parsing then using a typed value) while keeping immutability.

References

What's next

Next: Variable declarations and mutability.

From PHP to Rust — Rust Syntax and Functions