Nick Cosentino @DevLeaderCa posted this message about recursion on X, ex Twitter, in October 2025, which received over 460 replies.
I quote an excerpt: I've found that converting over to an iterative loop based approach is almost always more readable and easier to debug. He explains that in over 20 years of programming, he has never used recursion, thus questioning its usefulness.
In this article, I show a real case where I used recursion, and where I think that it is much simpler than its iterative counterpart.
But before going any further, let see what makes a recursive algorithm powerful.
The Fibonacci sequence
To understand the value of recursion, let's look at the implementations with and without recursion of an algorithm very often used to illustrate it: the Fibonacci sequence.
Here's the recursive algorithm.
if n = 0 or n = 1 then
fib(n) = 1
else
fib(n) = fib(n − 1) + fib(n − 2)
endif
And here's the iterative one.
if n = 0 or n = 1 then
fib(n) = 1
else
a = 1
b = 1
for i in 2 .. n do
c = a + b
a = b
b = c
endfor
fib(n) = c
endif
This simple example demonstrates the advantages of recursion: no loops and no intermediate variables.
This also gives us an indication of when recursion is advantageous, namely when the function can be defined with a simple expression depending on itself. This might not be the case for example when the data being processed is a graph instead of a tree.
Our problem
The library we'll be talking about is the PHP UI Builder. It builds application UIs using components, as defined by CSS frameworks. It provides a common API which defines the components, and from which specialized libraries can generate HTML code for a given CSS framework, like Bootstrap, Bulma or Tailwind CSS.
The UI components
With its hierarchical component structure, a UI is particularly well-suited to a recursive algorithm. A component has properties, but can also contain components that themselves have some properties and can contain other components, and so on.
The virtual components
When building a UI from data, the result can sometimes vary depending on their values. Some components will only be created under certain conditions, others are multiplied according to the entries in a list or loop, and others may be an aggregate of different components.
To represent these cases, our library introduces the concept of virtual components. These are components that take a set of data as input and produce as output a set of zero or more components, which may or may not be virtual.
There are 4 of them:
- When: takes a condition as input and generates a component if it is met.
- Each: takes an array of data as input and generates a component for each element.
- Pick: takes a list of conditions as input and generates a different component depending on the first one that is true.
- List: aggregates any set of components into one.
A UI will ultimately consist of a tree structure of components, each of which can be virtual or real. A real component can have several children, each of which can be virtual or real, and a virtual component generates a list of components, each of which can be virtual or real.
Here's an example of a function using the UI library.
/**
* @param array $collations
*
* @return string
*/
public function addDbForm(array $collations): string
{
return $this->ui->build(
$this->ui->form(
$this->ui->row(
$this->ui->col(
$this->ui->label($this->ui->text('Name'))
->setFor('name')
)->unit(1, 4),
$this->ui->col(
$this->ui->input()
->setType('text')
->setName('name')
)->unit(1, 2)
),
$this->ui->when(count($collations) === 0, fn() =>
$this->ui->input()
->setType('hidden')
->setName('collation')
->setValue('')),
$this->ui->when(count($collations) > 0, fn() =>
$this->ui->row(
$this->ui->col(
$this->ui->label($this->ui->text('Collation'))
->setFor('collation')
)->unit(1, 4),
$this->ui->col(
$this->ui->select(
$this->ui->option('(collation)')
->setValue('')
->selected(true),
$this->ui->each($collations, fn($_collations, $group) =>
$this->ui->pick(
$this->ui->when($group === '', fn() =>
$this->ui->each($_collations, fn($collation) =>
$this->ui->option($collation)
)
),
$this->ui->when(true, fn() =>
$this->ui->optgroup(
$this->ui->each($_collations, fn($collation) =>
$this->ui->option($collation)
)
)->setLabel($group)
)
)
)
)->setName('collation')
)->width(6)
)
)
)
);
}
The processing algorithm
To generate a UI from a component tree, we will use the following algorithm:
function build(c)
children = []
expand(c, children)
c.elements = []
for child in children
if child is a component then
build(child)
append child.elements to c.elements
else
append child to c.elements
endif
endfor
endfunction
function expand(c, children)
if c is virtual then
for child in c.children
expand(child, children)
endfor
else
append c to children
endif
endfunction
What we have here is actually a combination of two recursive functions.
The expand() function returns the list of real components generated by a virtual component. It will therefore iterate recursively over all its children as long as virtual components are present.
The build() function, which is the entry point for the process, first calls the expand() function. Its list of children then consists only of real components, on which it executes recursively.
The final result is in the Scope class. In their PHP implementation, the recursive expand() function is 15 lines of code long, and the build() function is 40.
Two extremely simple functions, which form the basis that allows the implementation in a single library of both the templating functionalities of libraries such as Twig or Blade, and the HTML code generation of libraries such as Spatie's HTML Builder or Symfony's Forms component (the rendering part).
The UI library is used to build the Jaxon DbAdmin UI, demonstrating that it allows the construction of complex UIs, calling classes and their methods instead of writing HTML templates.
The limitations of recursion
Nick Cosentino's message rightly points out two drawbacks of recursion, which we will briefly discuss here.
Debugging
First, it's absolutely true that recursion is difficult to debug, particularly because mentally unraveling the instructions executed by a recursive algorithm is very complex. However, at the same time, the simplicity of recursive algorithms leaves little chance for a bug to occur.
Therefore, before choosing recursion, it's important to ensure that the algorithm being implemented can be expressed very simply in a recursive manner. This is indeed the case for the Fibonacci sequence and our library.
Memory usage
Implementing a recursive algorithm can consume a significant amount of memory, depending on the level of nesting of the calls.
For our UI library, the level of nesting of an application's UI components will always be very limited, and even more if it is built one part at a time, each in a separate recursive function call.
Moreover, PHP imposes a limit on the number of nested calls within a recursive function, and the consequence of an overflow will be to fail a single call, not to crash the entire server.
The closing word
To answer Nick Cosentino's initial question, of course it is possible to create all sorts of complex software without using recursion.
However, this doesn't mean it can always be replaced by an iterative version, but rather that cases where one can fully leverage all its advantages are not very common.

Top comments (0)