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

In PHP, a class usually bundles properties and methods in one class Rectangle { ... } block. Rust splits that into two pieces: a struct (or enum) for data, and one or more impl TypeName { ... } blocks for functions that belong to that type. The ideas map well: instance methods ≈ methods with $this, and associated functions (no self) ≈ static methods.

Methods: $this becomes explicit self

In PHP, $this is implicit inside instance methods. In Rust, the receiver is the first parameter, with special syntax:

Rust receiver Rough PHP mental model
&self Read-only use of $this (you don’t reassign $this, you only read properties / call other methods).
&mut self Mutating $this’s fields (like changing properties on the object).
self Taking ownership of the value (no direct PHP equivalent for “value types”; common when a method consumes the struct, e.g. builder patterns).

Calling rect.area() is syntactic sugar: the compiler turns it into something like Rectangle::area(&rect), so you can always think “method = function that takes the instance as first argument.”

Associated functions: like public static function

If a function in an impl block does not take self, &self, or &mut self, it is an associated function, not called on an instance with ., but on the type with ::.

That matches PHP static methods:

  • PHP: Rectangle::square(3)
  • Rust: Rectangle::square(3)

Inside impl Rectangle, Self means “this type” (here, Rectangle), similar to PHP’s self return type for new self(...).

. vs :: (quick rule)

  • value.method(...), instance method (has self / &self / &mut self).
  • Type::name(...), associated function or explicitly calling a method with the type on the left (e.g. Rectangle::area(&rect)).

Why impl is separate from struct

You’ll often see struct + impl back-to-back in one file; it still isn’t one keyword like class. That separation matters later: you can have several impl blocks for the same type, split methods across modules, and control visibility (pub) on methods and fields independently, similar in spirit to choosing what’s public on a PHP class, but enforced by the compiler.

Rust

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
    fn square(size: u32) -> Self {
        Rectangle { width: size, height: size }
    }
}

fn main() {
    let rect = Rectangle { width: 30, height: 50 };
    println!("Area: {}", rect.area());
    let sq = Rectangle::square(3);
    println!("Square area: {}", sq.area());
    println!("rect can hold sq? {}", rect.can_hold(&sq));
}

PHP

<?php
class Rectangle {
    public function __construct(
        public int $width,
        public int $height,
    ) {}

    public function area(): int {
        return $this->width * $this->height;
    }

    public function canHold(Rectangle $other): bool {
        return $this->width > $other->width && $this->height > $other->height;
    }

    public static function square(int $size): self {
        return new self($size, $size);
    }
}

$rect = new Rectangle(30, 50);
echo "Area: {$rect->area()}\n";
$sq = Rectangle::square(3);
echo "Square area: {$sq->area()}\n";
echo 'rect can hold sq? ' . ($rect->canHold($sq) ? "true\n" : "false\n");

Comparison

  • Rust: Data in struct, behaviour in impl Type { ... }. Receiver explicit: &self / &mut self / self. No this keyword.
  • PHP: Data + behaviour in one class. $this implicit in instance methods; static for type-level functions.
  • Rust: Functions without self are associated functions, called with Type::name(...).
  • PHP: static methods are the closest match; call with Type::name(...) or static:: from inside the class.
  • Rust: Self in impl Rectangle = the type being implemented (like PHP self for return/static factory).

References

What's next

Next: Enums.

From PHP to Rust — Rust Syntax and Functions