---
title: "PHP Method Resolution Order: Class · Trait · Parent · Interface"
url: https://www.exakat.io/php-method-resolution-order-class-%c2%b7-trait-%c2%b7-parent-%c2%b7-interface/
date: 2026-08-18
modified: 2026-08-18
author: "dams"
description: "PHP Method Resolution Order: Class · Trait · Parent · Interface PHP offers three different places to define a method: directly in a class, in a trait the class uses,..."
categories:
  - "Code auditing"
tags:
  - "method"
  - "oop"
  - "php"
image: https://www.exakat.io/wp-content/uploads/2026/08/pumpkin.320-1024x769.jpg
word_count: 1073
---

# PHP Method Resolution Order: Class · Trait · Parent · Interface

# PHP Method Resolution Order: Class · Trait · Parent · Interface

PHP offers three different places to define a method: directly in a class, in a trait the class uses, and in a parent class it extends. Interfaces define contracts, the method signatures without a body, so they don't contribute an implementation to the chain, though they handle other aspects. When more than one layer defines the same method name, PHP needs a clear rule for which one wins. That rule is the `method resolution order`, also know as **[MRO](https://php-dictionary.readthedocs.io/en/latest/index/mro.html?highlight=mro#method-resolution-order-mro)**.

Understanding it removes an entire class of subtle bugs: the ones where you override a method and nothing seems to change, or where adding a trait silently overwrites behaviour you meant to keep from the parent.

## The priority stack

Think of it as a stack of layers. PHP looks from top to bottom and uses the first definition it finds. The class sits at the top, with the highest priority, and the parent class sits at the bottom. Interfaces are not part of the resolution chain; they only enforce that a method exists somewhere.

| Priority | Layer | Description |
| -------- | ----- | ----------- |
| **1 — highest** | **Class — own method** | Always wins. Defined directly in the class body. |
| **2** | **Trait method** | Used when the class has no own definition. PHP copies it in at compile time. |
| **3 — lowest** | **Parent class method** | Inherited via `extends`. Overridden by any layer above. |

Each layer overrides everything below it. Remove a layer and PHP drops down to the next one automatically.

## A concrete example

Here is a minimal setup with all three layers defining the same method `greet()`, plus an interface that enforces the contract:

Remove the own method from `App` and the trait takes over. Remove the trait and the parent shows up. The interface only guarantees the method must exist: it never provides an implementation, only a signature.

## The rules that catch people out

### Trait beats parent

PHP copies trait methods directly into the class body at compile time, so they are treated as if you wrote them there. A parent's method is merely inherited and therefore lower in the hierarchy.

## Class beats trait

An explicit definition in the class itself always takes precedence over anything brought in via `use`. The trait is a default the class can override without touching the trait source. There is no way to override this: trait naming resolution operator allows aliasing a method, though.

### Conflicting traits are a fatal error

When two `use`'d traits define the same method, PHP throws a fatal error at class definition time. You must resolve it explicitly with `insteadof` or alias one with `as`.

### Interface are a contract, never an implementation

PHP interfaces only declare method signatures. If no layer in the class hierarchy provides an implementation, you get a fatal error at instantiation time. The interface enforces the shape; the class, or the trait, or the parent, anyone really, must provide the substance.

## Resolving a trait conflict

When two traits collide, use `insteadof` to choose a winner and optionally `as` to keep both under different names:

## Calling up the chain

Between classes, you can call the method from the next layer down using `parent::`. This is useful when you want to extend behaviour rather than replace it entirely:

This only works on extended classes, and it will reach the first defined method, from a trait or not. This means that some classes may be skipped, if they are not providing a definition for the needed method. Ultimately, it yields an 'undefined error'.

## Calling the trait on the side

If calling the parent requires using the `parent` keyword, there is no such keyword for the overridden trait. When an eponynous method is defined, the trait's version is just not reachable. For that, the only solution is to alias the trait's method, and access it from the class.

## Side note: enums

Enums follow exactly the same rules as classes for traits and interfaces: they can `use` traits and `implement` interfaces, and the same resolution order applies. The one difference: enums just cannot `extend` a parent class. There is no parent layer for an enum, so the chain is shorter:

own method > trait

## The mental model

When you call a method on an object, imagine PHP walking down the stack from the class toward the parent, stopping as soon as it finds a definition. The class is the most specific context: it knows the most about what this particular type should do. The parent is the most general implementation: it provides the baseline behaviour. The interface sits outside this chain entirely; it only enforces that the method exists somewhere. Priority follows specificity.

Keep that picture in mind and the resolution order stops being something to memorise and becomes something you can reason about from first principles.

There are some attempts at building a `grandparent` [operator](https://php-tips.readthedocs.io/en/latest/tips/parent_operator.html), though, it requires some courage.