Step 1 of 7 · Reading · ~5 min
Learn
Classes, Inheritance, Errors
Classes and Objects
Every value you have handled so far has been a number, a string, or an array. A class lets you invent a new kind of value: a name for some data, together with the operations that belong with it. PHP has been object-oriented since PHP 5, and everything in the language above the level of a single script is built on classes.
Defining a class
<?php
class Parcel {
public string $tracking;
public int $grams;
public function __construct(string $tracking, int $grams) {
$this->tracking = $tracking;
$this->grams = $grams;
}
public function label(): string {
return "{$this->tracking} ({$this->grams}g)";
}
}
$p = new Parcel('LX4471', 850);
echo $p->label(), "\n";
echo $p->tracking, "\n";
//> LX4471 (850g)
//> LX4471
| Piece | What it means |
|---|---|
class Parcel { ... } | defines the new type |
public string $tracking; | a typed property, declared in the class body (PHP 7.4+) |
__construct | runs automatically when you write new |
$this | the object the method was called on — note the $ |
-> | reaches a property or a method |
:: | reaches a static member instead |
Declare the property in the class body, then assign it in the constructor. Those two steps are the shape every exercise in this chapter expects.
Visibility: what the outside world may touch
<?php
class Depot {
private int $capacity;
public string $city;
public function __construct(string $city, int $capacity) {
$this->city = $city;
$this->capacity = $capacity;
}
public function accept(int $parcels): bool {
if ($parcels > $this->capacity) {
return false;
}
$this->capacity -= $parcels;
return true;
}
public function remaining(): int {
return $this->capacity;
}
}
$d = new Depot('Lisbon', 100);
var_dump($d->accept(30));
var_dump($d->accept(200));
echo $d->remaining(), "\n";
echo $d->city, "\n";
//> bool(true)
//> bool(false)
//> 70
//> Lisbon
| Modifier | Who can reach it |
|---|---|
public | anyone, from anywhere |
protected | this class and any class extending it |
private | this class only |
The reason $capacity is private shows up in accept(): the only route to changing it is a method that checks first, so the depot can never be over-filled. Reach past that from outside and PHP refuses — reading $d->capacity at the top level stops the program with Error: Cannot access private property Depot::$capacity.
Default to private for properties and let methods decide what callers may do. That is not ceremony; it is the only way to keep a rule like "capacity never goes negative" true.
The PHP 8 shorthand you will meet in real code
Grader note: PHP 8.0 added constructor property promotion —
public function __construct(private int $cents) {}declares the property and assigns it in a single stroke — and PHP 8.1 addedreadonlyfor write-once properties. Both are parse errors on this course's PHP 7.4 grader, which answerssyntax error, unexpected 'private' (T_PRIVATE), expecting variable (T_VARIABLE)and then runs none of your file. Learn to read them, because modern codebases are full of them; write the two-step form shown above in the exercises here.
Static members belong to the class
<?php
class Scanner {
private static int $scans = 0;
public static function record(): void {
self::$scans++;
}
public static function total(): int {
return self::$scans;
}
}
Scanner::record();
Scanner::record();
Scanner::record();
echo Scanner::total(), "\n";
//> 3
staticputs the member on the class, so there is exactly one copy however many objects exist.self::means "the class this code is written in". A static property keeps its dollar sign after it:self::$scans.- A static method has no
$this, because it was never called on an object.
Class constants
<?php
class Tier {
const STANDARD = 'standard';
const EXPRESS = 'express';
const SURCHARGE = 9;
}
echo Tier::EXPRESS, "\n";
echo Tier::SURCHARGE + 1, "\n";
//> express
//> 10
A constant carries no dollar sign, can never be reassigned, and is read with :: from anywhere. On PHP 7.4 this is how you write a fixed set of options. PHP 8.1 added real enum types; enum is not a keyword at all on this grader, so an enum declaration is a parse error here.
__toString: using an object where a string is expected
<?php
class Money {
private int $cents;
public function __construct(int $cents) {
$this->cents = $cents;
}
public function __toString(): string {
return sprintf('%.2f EUR', $this->cents / 100);
}
}
$m = new Money(12345);
echo $m, "\n";
echo "total: $m\n";
//> 123.45 EUR
//> total: 123.45 EUR
__toString() runs whenever the object lands in a string context — echo, interpolation, concatenation. It has to return a string; returning anything else is a fatal error. Note what this buys: Money stores an exact integer number of cents and never touches a float, yet it still prints like money.
Common mistakes
- Forgetting
$this->— a bare$gramsinside a method is a local variable that merely shares a name with your property. - Using
.where->belongs —.concatenates strings, so$p.label()becomes a puzzle instead of a method call. - Using
=>where->belongs —=>builds array entries and has nothing to do with objects. - Using
->on a static member — statics wantScanner::total()from outside andself::$scansfrom inside. - Assigning to a property you never declared — PHP 7.4 allows it, quietly creating an untyped property and discarding the checking you wrote the class body for.
Your exercise
Rectangle Class wants a Rectangle holding private int $width and int $height, a constructor that stores both, an area() returning their product, and a perimeter() returning 2 * ($width + $height). The starter already reads the two numbers and leaves the object lines commented out for you.
The mistake the grader catches is the PHP 8 shorthand: __construct(private int $width, private int $height) {} is a parse error here, so the program never starts and all three tests fail at once. Declare both properties in the class body and assign them with $this->width = $width;. The second trap is the output shape — two lines, area: 15 then perimeter: 16 for the first test's 5 by 3 rectangle, lower-case labels, one space after each colon, and a "\n" closing both of them.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…