PHPProperties & Methods

Properties & Methods

Properties are the variables that belong to a class, and methods are the functions that belong to it. Together they are what a class actually is: properties hold an object's state, and methods define how that state can be read, changed, or acted on. This page digs into how to declare properties properly — with types and defaults — and into a scoping mistake that trips up almost everyone the first time they meet it.

Declaring typed properties

Since PHP 7.4, properties can (and should) carry a type declaration, the same way function parameters can. A typed property rejects assignments of the wrong kind of value, which catches mistakes far earlier than an untyped property would.

Product with typed properties

PHP
<?php
class Product
{
    public string $name;
    public float $price;
    private float $taxRate;
}

$product = new Product();
$product->name = 'Wireless Mouse';
$product->price = 25.00;

// $product->price = 'expensive'; // Fatal error: Cannot assign string to
                                    // property Product::$price of type float

public string $name reads as "a public property named $name, which must hold a string." Trying to assign an incompatible value to a typed property is a hard error, not a silent coercion — PHP would rather stop you than let a Product end up with a price that is actually the string 'expensive'.

Giving properties default values

A property can be given a default value right in its declaration. Any object created from the class starts with that value already in place, so you do not have to set it manually every time — only where it needs to differ from the default.

Defaults mean fewer things to set by hand

PHP
<?php
class Product
{
    public string $name = 'Untitled product';
    public float $price = 0.0;
    private float $taxRate = 0.08; // most products use the standard rate
}

$product = new Product();
echo $product->name . ': $' . $product->price . "\n";

$product->name = 'Wireless Mouse';
$product->price = 25.00;
echo $product->name . ': $' . $product->price . "\n";
Untitled product: $0
Wireless Mouse: $25

Note that default values must be simple, fixed expressions known at compile time — a literal, a constant, or a simple calculation on literals. You cannot default a property to the result of calling a function; that kind of setup belongs in the constructor instead, which the next page covers.

Methods act on $this

A method is just a function defined inside a class, and inside it, $this is how you reach the current object's own properties. Here, applyDiscount() mutates the object's price property directly.

A method that changes the object's own state

PHP
<?php
class Product
{
    public string $name = 'Untitled product';
    public float $price = 0.0;

    public function applyDiscount(float $percentOff): void
    {
        $this->price = round($this->price * (1 - $percentOff / 100), 2);
    }
}

$product = new Product();
$product->name = 'Wireless Mouse';
$product->price = 25.00;

$product->applyDiscount(20);

echo $product->name . ': $' . $product->price . "\n";
Wireless Mouse: $20
The property-vs-local-variable pitfall

Inside a method, a bare $price and $this->price are two completely different variables that happen to share a name. $price is a local variable that lives only for the duration of the method call; $this->price is the object's property. Forgetting $this-> does not raise an error — PHP happily creates a brand new local variable instead, silently, and the property is never touched.

Forgetting $this-> silently breaks the update

PHP
<?php
class Product
{
    public float $price = 25.00;

    public function applyDiscountBroken(float $percentOff): void
    {
        // BUG: assigns to a local variable, not the property
        $price = round($price * (1 - $percentOff / 100), 2);
    }

    public function applyDiscountFixed(float $percentOff): void
    {
        $this->price = round($this->price * (1 - $percentOff / 100), 2);
    }
}

$product = new Product();
$product->applyDiscountBroken(20);
echo 'After broken discount: $' . $product->price . "\n";

$product->applyDiscountFixed(20);
echo 'After fixed discount: $' . $product->price . "\n";
After broken discount: $25
After fixed discount: $20

applyDiscountBroken() reads an undefined local $price (treated as null, triggering a warning in modern PHP), does some arithmetic on it, and stores the result in a local variable that vanishes the moment the method returns. The object's actual price property never changes.

Same name, different variable
A method parameter can make this worse: a method `setPrice(float $price)` has a parameter `$price` that shadows anything you might expect from the property. Inside that method, `$price` is the argument passed in, and you must still write `$this->price = $price;` to actually store it on the object.
  • Typed properties (public float $price) reject assignments of the wrong type with a fatal error.

  • Default values in a property declaration must be fixed, compile-time expressions.

  • Inside a method, $this->price is the object's property; $price alone is a separate local variable or parameter.

  • A method with the same-named parameter as a property must explicitly assign $this->prop = $param; — nothing does this automatically.

Uninitialized typed properties
A typed property declared without a default value (like `public string $name;` with no `= '...'`) has no value at all until something assigns one — reading it beforehand throws an `Error: Typed property must not be accessed before initialization`. Giving it a default, or setting it in a constructor, avoids this entirely.
Tip
When a bug looks like "my method ran but nothing changed," check for a missing `$this->` before anything else. It is one of the most common mistakes in early PHP OOP code, and it never produces an error — only a value that quietly failed to update.