Advent of code 2023/23
Ajax Direct

Answer 6894ms

Part 1 : 2366 Part 2 : 6682
function get_intersections_links($grid, $start, $end, $slopes = []) {
    $intersections = [$start, $end];
    foreach ($grid as $y=>$row) foreach ($row as $x=>$c) {
        if ($c == "#") continue;
        $paths = 0;
        foreach (neighbors([$x, $y]) as [$nx, $ny]) if (($grid[$ny][$nx]??"#") != "#") $paths++;
        if ($paths >= 3) $intersections[] = "$x;$y";
    }

    $links = [$start => [], $end => []];
    foreach ($intersections as $int) {
        $queue = [$int];
        while ($queue) {
            $current = array_pop($queue);
            $path    = explode("|", $current);
            [$x, $y] = explode(";", $path[count($path) - 1]);

            if ("$x;$y" != $int && in_array("$x;$y", $intersections)) {
                $links[$int]["$x;$y"] = max($links[$int]["$x;$y"]??0, count($path) - 1);
                continue;
            }

            foreach (neighbors([$x, $y]) as $dir=>[$nx, $ny]) {
                if (($grid[$ny][$nx]??"#") == "#") continue;
                if (in_array("$nx;$ny", $path)) continue;
                if (isset($slopes[$grid[$y][$x]]) && $slopes[$grid[$y][$x]] != $dir) continue;
                $queue[] = $current . "|$nx;$ny";
            }
        }
    }
    return $links;
}

function solve($links, $current, $end, $distance = 0, $visited = []) {
    if ($current == $end) return $distance;
    $visited[$current] = true;

    foreach ($links[$current] as $n=>$d) {
        if (isset($visited[$n])) continue;
        $max = max($max??0, solve($links, $n, $end, $distance + $d, $visited));
    }
    return $max??0;
}

// ==================================================
// > SOLVE
// ==================================================
$grid = (array) $input->lines->map("str_split");
[$w, $h] = [count($grid[0]), count($grid)];
[$start, $end] = ["1;0", ($w - 2) . ";" . ($h - 1)];

// Part 1
$solution_1 = solve(
    get_intersections_links($grid, $start, $end, [">" => "right", "<" => "left", "^" => "up", "v" => "down"]),
    $start, $end
);

// Part 2
$links = get_intersections_links($grid, $start, $end);
$offset = $links[$end] ? array_values($links[$end])[0] : 0;
$end = $links[$end] ? array_keys($links[$end])[0] : $end;
$solution_2 = solve($links, $start, $end) + $offset;