First you need to find all stages if this is not known up front and can be dynamic.
If you have that you can just build the table by iterating your data.
<?php
$data = [
'person1' => [
'stage1' => 4,
'stage2' => 4,
'stage3' => 4,
'stage4' => 4,
'stage5' => 2,
],
'person2' => [
'stage3' => 1,
],
'person3' => [
'stage1' => 2,
'stage2' => 1,
'stage4' => 1,
'stage5' => 2,
],
];
$stages = [];
foreach ($data as $person) {
foreach ($person as $stage => $number) {
if (!in_array($stage, $stages)) {
$stages[] = $stage;
}
}
}
var_dump($stages);
?>
<table>
<th>person</th>
<?php foreach ($stages as $stage): ?>
<th><?php echo $stage; ?></th>
<?php endforeach ?>
<?php foreach ($data as $personName => $person): ?>
<tr>
<td><?php echo $personName; ?></td>
<?php foreach ($stages as $stage): ?>
<td><?php echo $person[$stage] ?? 0; ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
And the result:
array(5) { [0]=> string(6) "stage1" [1]=> string(6) "stage2" [2]=> string(6) "stage3" [3]=> string(6) "stage4" [4]=> string(6) "stage5" }
person stage1 stage2 stage3 stage4 stage5
person1 4 4 4 4 2
person2 0 0 1 0 0
person3 2 1 0 1 2