Question

PHP new self vs new static: Understanding Late Static Binding

phpstaticlate-static-binding

Question

I am converting a PHP 5.3 library so it can run on PHP 5.2. One of the main issues is code that uses late static binding, such as:

return new static($options);

If I change that to:

return new self($options);

will it behave the same way?

What is the difference between new self and new static in PHP?

Short Answer

By the end of this page, you will understand how self and static behave differently in PHP class methods, especially when inheritance is involved. You will see why new self() creates an instance of the class where the code is written, while new static() creates an instance of the class that was actually called. This distinction is essential when working with parent and child classes, factory methods, and libraries that rely on extensibility.

Concept

In PHP, self and static can both refer to classes, but they are not resolved the same way.

  • self refers to the class where the method is defined.
  • static refers to the class used at runtime to call the method.

This difference matters in inherited code.

new self()

When you write:

return new self($options);

PHP creates an object of the class that contains that code. It does not change based on which subclass called the method.

new static()

When you write:

return new static($options);

PHP uses late static binding. That means PHP waits until runtime and creates an object of the actual called class.

Why this matters

If a base class contains a factory method and a child class inherits it:

  • new self() always returns the base class
  • new static() can return the child class

This is very important in reusable libraries, ORMs, fluent APIs, and factory patterns, where parent classes are designed to be extended.

PHP version note

Late static binding was introduced in PHP 5.3. PHP 5.2 does not support static in this way. So replacing new static() with new self() may make the code run, but it can also change behavior in inherited classes.

Mental Model

Think of self and static like two different ways of reading a label.

  • self says: "Use the class name printed in this file."
  • static says: "Use the class name of whoever actually called me."

Imagine a blueprint for a vehicle factory:

  • With new self(), the blueprint always says: "Build a Vehicle."
  • With new static(), the blueprint says: "Build whatever type of vehicle requested this method, such as Car or Truck."

So if Car inherits a method from Vehicle:

  • new self() still builds a Vehicle
  • new static() builds a Car

That is the key idea behind late static binding.

Take Quiz

Syntax and Examples

Here is the basic syntax:

self::methodName();
static::methodName();

new self();
new static();

Example 1: new self()

<?php

class Base {
    public static function make() {
        return new self();
    }
}

class Child extends Base {}

$object = Child::make();
echo get_class($object);

Output:

Base

Even though Child::make() was called, the method is defined in Base, so new self() creates a Base object.

Example 2: new static()

<?php

class Base {
    public static function make() {
        return new static();
    }
}

class Child extends Base {}

$object = Child::make();
echo get_class($object);

Output:

Child

This time, late static binding makes PHP create an object of the called class, which is Child.

Example 3: Why libraries use static

<?php

class Model {
    protected $data;

    public function __construct($data = array()) {
        $this->data = $data;
    }

    public static function create($data) {
        return new static($data);
    }
}

class User extends Model {}

$user = User::create(array('name' => 'Ava'));
echo get_class($user);

Output:

User

This is useful for reusable parent classes that should return subclass instances automatically.

Step by Step Execution

Consider this example:

<?php

class Animal {
    public static function build() {
        return new static();
    }
}

class Dog extends Animal {}

$pet = Dog::build();
echo get_class($pet);

Step by step

  1. PHP defines the Animal class.

  2. PHP defines the Dog class, which extends Animal.

  3. The code calls:

    Dog::build();
    
  4. PHP looks for build() in Dog.

  5. Dog does not define build(), so PHP uses the inherited method from Animal.

  6. Inside build(), the code says:

    return new static();
    
  7. Because static uses late static binding, PHP checks which class made the call at runtime.

  8. The call came from Dog, so PHP creates a Dog object.

  9. get_class($pet) returns:

    Dog
    

If you change it to new self()

<?php

class Animal {
    public static function build() {
        return new self();
    }
}

class Dog extends Animal {}

$pet = Dog::build();
echo get_class($pet);

Now the result is:

Animal

Why? Because self points to the class where build() was defined: Animal.

Real World Use Cases

This difference appears in many real applications.

1. Factory methods

A parent class may provide a helper like create() or make():

class Response {
    public static function make($data) {
        return new static($data);
    }
}

Subclasses such as JsonResponse or XmlResponse can inherit the method and still get the correct type.

2. ORM and Active Record models

Database libraries often use parent model classes:

$user = User::create($row);

If the base model uses new static(), the returned object is a User, not just a generic Model.

3. Fluent APIs and builders

Some class methods return a new instance of the current subclass.

4. Reusable library code

When writing extendable frameworks, base classes should often respect inheritance. static helps preserve subclass behavior.

5. Named constructors

Methods like fromArray(), fromJson(), or createFromConfig() often need to return the called class:

class Config {
    public static function fromArray($data) {
        return new static($data);
    }
}
Take Quiz

Real Codebase Usage

In real codebases, developers choose between self and static based on whether inheritance should affect the result.

Use self when the method is intentionally fixed to the base class

class Token {
    public static function internalFactory() {
        return new self();
    }
}

This is appropriate when you do not want subclasses to change the returned type.

Use static when the class is designed for extension

class Collection {
    public static function fromArray($items) {
        return new static($items);
    }
}

This is common in libraries that expect child classes.

Common patterns

  • Named constructors: fromArray(), fromString(), create()
  • Factory methods: return subclass instances correctly
  • Extensible base models: ORMs, entities, records
  • Framework base classes: reusable logic in parent classes

Migration consideration for PHP 5.2

If your PHP 5.3 code relies on new static(), replacing it with new self() is only safe if:

  • the class is never subclassed, or
  • returning the parent class is acceptable

If subclasses depend on correct late-bound instances, behavior will change and may break the library.

In PHP 5.2, developers sometimes worked around this by:

  • passing class names explicitly
  • overriding factory methods in each subclass
  • using get_class() or string class names carefully

Those workarounds are more manual and less elegant than late static binding.

Common Mistakes

1. Assuming self and static are interchangeable

They are not the same when inheritance is involved.

Broken expectation:

<?php

class ParentClass {
    public static function make() {
        return new self();
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::make();
echo get_class($obj); // ParentClass, not ChildClass

2. Replacing new static() with new self() during migration without checking subclass usage

This may silently change returned object types.

How to avoid it:

  • inspect whether classes are extended
  • inspect whether factory methods are inherited
  • test returned object types with get_class() or instanceof

3. Using static in PHP 5.2

This syntax is not available for late static binding in PHP 5.2.

4. Forgetting constructor compatibility

If a parent method does this:

return new static($options);

then child classes must be able to accept the same constructor arguments, or object creation may fail.

5. Confusing self:: with static::

The same late-binding idea applies to static method calls too.

self::who();
static::who();

static::who() can resolve to an overridden child method, while self::who() points to the current class definition.

Comparisons

Conceptselfstatic
Resolution timeCompile-time style class referenceRuntime class reference
Inheritance-awareNoYes
new behaviorCreates the defining classCreates the called class
Works with late static bindingNoYes
Available in PHP 5.2 for this behaviorself worksLate static binding does not
Best forFixed base-class behaviorExtendable library behavior

new self() vs new static()

class A {
    public static function makeSelf() {
        return new self();
    }

    public static function makeStatic() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::makeSelf());   // A
echo get_class(B::makeStatic()); // B

When to choose each

  • Choose self when the method should always return the exact class where it is defined.
  • Choose static when inherited classes should get their own type back.
Take Quiz

Cheat Sheet

  • new self() = create an instance of the class where the code is written
  • new static() = create an instance of the class used to call the method
  • self does not support late static binding
  • static does support late static binding
  • new static() requires PHP 5.3+
  • Replacing new static() with new self() can change behavior in subclasses

Quick example

class Base {
    public static function a() { return new self(); }
    public static function b() { return new static(); }
}

class Child extends Base {}

get_class(Child::a()); // Base
get_class(Child::b()); // Child

Rule of thumb

  • Use self for fixed behavior
  • Use static for inheritance-friendly behavior

Migration warning for PHP 5.2

If the original code depended on subclass-aware factories, self is not a true replacement for static.

FAQ

Does new self() always return the parent class?

It returns the class where that code is defined. If the method is defined in a parent class, then yes, it returns the parent class.

Does new static() work in PHP 5.2?

No. Late static binding was introduced in PHP 5.3.

Can I safely replace new static() with new self()?

Only if inheritance does not matter for that code path. Otherwise, the returned object type may change.

Why do frameworks and libraries often use static?

Because they are designed to be extended, and they want inherited methods to return subclass instances.

What is late static binding in simple terms?

It means PHP decides the class at runtime based on who made the call, rather than the class where the code was originally written.

Is the same idea true for self::method() and static::method()?

Yes. static::method() uses late static binding, while self::method() refers to the defining class.

What should I do in PHP 5.2 if I need subclass-aware factories?

You may need manual workarounds, such as overriding the method in each subclass or passing class names explicitly.

Take Quiz

Mini Project

Description

Build a small PHP example that demonstrates how inherited factory methods behave with new self() and new static(). This project is useful because it shows the exact situation that often appears in reusable libraries and older PHP migrations.

Goal

Create parent and child classes, call inherited factory methods, and observe how the returned object type changes depending on whether self or static is used.

Requirements

  • Create a parent class with one factory method that uses new self()
  • Create a second factory method that uses new static()
  • Create a child class that extends the parent class
  • Call both factory methods from the child class
  • Print the class name of each returned object
Take Quiz

Keep learning

Related questions

View more