PHP Descending Number Triangle Pattern

Beginner
5 min read
Updated: Sep 2026
3 programs
Live preview

What Is This Pattern?

A descending number triangle prints digits 1..i on each row, with the outer loop counting down so the first row is longest.

Remember
Rule: for i = n..1, print 1..i

12345
1234
123
12
1       ← 5 rows

In PHP you solve it with two nested for loops: the outer loop picks the row length, the inner loop prints digits with echo $j, then echo PHP_EOL ends the row. Flip the outer loop upward for an ascending triangle (Program 5).

How to Solve It

Outer loop counts down from $rows to 1. Inner loop prints digits 1..i. End each row with echo PHP_EOL.

MethodIdeaBest for
Nested loopsOuter = length n..1, inner = digits 1..i via echoLearning, interviews, exams
Spaced digitsecho $j . " " instead of echo $jEasier reading on each row

Pseudocode

Pseudocode
for i from rows down to 1:
    for j from 1 to i:
        print j (no newline)
    print newline

Cheat sheet

GoalPattern
Shrink each rowfor ($i = $rows; $i >= 1; $i--)
Print digits 1..ifor ($j = 1; $j <= $i; $j++) echo $j;
End the rowecho PHP_EOL;
Spaced formecho $j . " ";
Ascending insteadfor ($i = 1; $i <= $rows; $i++) with the same inner loop

Printing Numbers vs Starting a New Line

APIEffectUse for
echo $jStays on the same lineEach digit $j
echo PHP_EOLEnds the current lineAfter the inner loop

Print all digits without a newline, then end the row once.

Live Preview

Change the row count and the descending triangle updates instantly — capped at 9 so every digit stays a single character.

Whole numbers from 1 to 9. Tap a chip or type a value — the preview redraws as you go.

Live result 5 rows · 15 digits
12345
1234
123
12
1

Worked Walkthrough

Trace $rows = 4 — each outer-loop value of $i and the digits the inner loop prints.

$iInner $jPrinted rowDigits
41..412344
31..31233
21..2122
11..111

Total digits are 4+3+2+1 = 10 — the triangular number n(n+1)/2.

PHP Programs

Three complete programs: fixed height, CLI input, and a spaced-digit variant. Use View Output for sample results.

Example 1 — Fixed $rows = 5

Outer loop shrinks the length; inner loop prints digits 1..i.

PHP
<?php
$rows = 5;

for ($i = $rows; $i >= 1; $i--) {
    for ($j = 1; $j <= $i; $j++) {
        echo $j;
    }
    echo PHP_EOL;
}
?>

How It Works

1. Shrink the count. for ($i = $rows; $i >= 1; $i--) yields 5, 4, 3, 2, 1.

2. Print digits. When $i = 5, the inner loop prints 12345; when $i = 1, just 1.

3. Newline. echo PHP_EOL; after the inner loop starts the next shorter row.

Example 2 — User Input

Read the row count from the CLI. Prefer is_numeric in real apps (shown in the tip below).

PHP
<?php
echo "Enter the number of rows: ";
$rows = (int) trim(fgets(STDIN));

for ($i = $rows; $i >= 1; $i--) {
    for ($j = 1; $j <= $i; $j++) {
        echo $j;
    }
    echo PHP_EOL;
}
?>

How It Works

1. Read rows. Ask for a row count, then trim(fgets(STDIN)) and cast to int.

2. Same nested loops. Four rows start at 1234 and end at 1.

3. Safer input tip. Bare (int) casts turn letters into 0. Prefer:

Safer input
echo "Enter the number of rows: ";
$input = trim(fgets(STDIN));
if (!is_numeric($input) || (int) $input < 1) {
    echo "Enter a positive whole number." . PHP_EOL;
    exit(1);
}
$rows = (int) $input;

Example 3 — Spaced Digits

Same loops with a trailing space so digits are easier to read.

PHP
<?php
$rows = 5;

for ($i = $rows; $i >= 1; $i--) {
    for ($j = 1; $j <= $i; $j++) {
        echo $j . " ";
    }
    echo PHP_EOL;
}
?>

How It Works

1. Same structure. Only the print expression changes — loops stay identical to Example 1.

2. Space after each digit. echo $j . " " separates values for clearer scanning.

3. When to use it. Prefer the tight form for classic screenshots; use spaced form when teaching or tracing by hand.

Edge Cases & Pitfalls

Check these before calling the solution done.

grow not shrink

for ($i = 1; $i <= $rows; $i++)

That outer loop grows the triangle (1, 12, 123…). Keep $i = $rows; $i >= 1; $i-- for this pattern.

PHP_EOL inside

echo PHP_EOL inside the inner loop

That puts each digit on its own line. Print digits without a newline; call echo PHP_EOL only after the row finishes.

off-by-one

$j < $i instead of $j <= $i

You drop the last digit on every row (e.g. 1234 becomes 123).

rows = 1

Single 1

Output is just 1 — a good sanity check.

rows ≤ 0

Empty output

The outer loop never runs. Validate and prompt again for clearer UX.

fgets

Check is_numeric

Bare (int) casts turn non-numeric strings into 0 — prefer is_numeric before casting.

Time and Space Complexity

ProgramTimeExtra space
Fixed / input (Examples 1–2)O(n²)O(1)
Spaced digits (Example 3)O(n²)O(1)

There are n rows printing n+(n-1)+…+1 digits, so total work is n(n+1)/2.

Key Takeaways

  • Rule: for $i = n..1, print digits 1..i with echo.
  • Count down: the outer loop starts at $rows so the first line is longest.
  • echo vs PHP_EOL: digits stay on the line; echo PHP_EOL advances after each row.
  • Next step: Program 2 shifts the start digit left each row.

One line: for each length from n down to 1, print 1..i with echo, then echo PHP_EOL.

Frequently Asked Questions

The outer loop runs i from rows down to 1. For each row i, the inner loop runs j from 1 to i and prints j with echo. Row rows prints 1..rows, the next row prints one fewer digit, down to a single 1.
Counting down makes the first row the longest. for ($i = $rows; $i >= 1; $i--) sets i to the full width first, then shrinks by one each line — matching 12345, 1234, 123, 12, 1.
echo $j sends output without adding a line break. echo PHP_EOL ends the current line with a portable newline. Digits use echo; the row break uses echo PHP_EOL after the inner loop.
Change the outer loop to for ($i = 1; $i <= $rows; $i++). Keep the inner loop as for ($j = 1; $j <= $i; $j++) echo $j. The first row then has one digit and the last row has rows digits — that is Program 5.
O(n²) where n is the number of rows. Total echo calls equal 1+2+…+n = n(n+1)/2.
Yes. echo chr(ord('0') + $j) writes one digit when j is 1..9. Nested loops with chr output are a common shortcut; keep echo $j if your course examples use it.
Use trim(fgets(STDIN)) and check is_numeric($input) before casting to int so bad input does not produce unexpected results.
The outer loop never runs, so nothing is printed. Validate and prompt again if you want a clear user message.

Did you know?

Row i prints digits 1 through i. The outer loop counts down from rows, so the first line is longest and each row shortens by one digit — still O(n²) total prints. This is the classic first console pattern in PHP labs.

Next: Left-Shifted Number Triangle

Keep a descending width, but shift the starting digit on each row.

Program 2 tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

12 people found this page helpful