Advent of code 2021/9
Ajax Direct

Answer 258ms

Part 1 : 486 Part 2 : 1059300
$grid = grid($input);

// ==================================================
// > PART 1
// ==================================================
$lowpoints = $grid->map(function ($val, $xy) use ($grid) {
    if (int($grid->getNeighbors($xy)->remove([null])->min()) > int($val)) {
        return int($val) + 1;
    }
    return 0;
})->cells();

$solution_1 = $lowpoints->sum();

// ==================================================
// > PART 2
// ==================================================
$basins = $lowpoints->filter()->keys()->map(function ($lp) use ($grid) {
    $queue = [$lp];
    $seen  = [];

    while ($queue) {
        $visit = array_shift($queue);
        $seen[] = $visit;

        $queue = array_merge($queue, (array) $grid->getNeighbors(explode(";", $visit))
            ->remove([null, 9], true)->keys()
            ->remove($seen)->remove($queue));
    }

    return count($seen);
});

$solution_2 = $basins->sort()->reverse()->slice(0, 3)->multiply();