Advent of code 2023/10
Ajax Direct

Answer 7ms

Part 1 : 7173 Part 2 : 291
$row = strpos($input, "\n");
$grid = str_split(str_replace("\n", "", $input));
$pipes = [
    "|" => [-$row, $row],  "-" => [-1, 1],
    "L" => [-$row, 1],     "F" => [$row, 1],
    "7" => [$row, -1],     "J" => [-$row, -1],
    "S" => [$row, -$row, -1, 1],
];

function get_next($pos, $grid, $pipes, $seen) {
    $next = [];
    foreach ($pipes[$grid[$pos]] as $move) $next[] = $pos + $move;

    if ($grid[$pos] == "S") foreach ($next as $n)
        foreach ($pipes[$grid[$n]] as $move)
            if ($n + $move == $pos) return $n;

    foreach ($next as $n) if (!isset($seen[$n])) return $n;
    return null;
}

// ==================================================
// > PART 1
// ==================================================
$pos = strpos($input, "S") - 1;
$seen = [$pos => ($d = 0)];
while (($pos = get_next($pos, $grid, $pipes, $seen)) != null) {
    $seen[$pos] = ++$d;
}
$solution_1 = (count($seen)) / 2;

// ==================================================
// > PART 2
// ==================================================
$solution_2 = 0;
foreach ($grid as $i=>$p) {
    if ($i % $row == 0) $o = 0;
    if (!isset($seen[$i])) {
        if ($o % 2) $solution_2++;
    } else {
        if ($p == "|") $o += 1;
        if ($p == "J" || $p == "F") $o += .5;
        if ($p == "L" || $p == "7") $o -= .5;
    }
}