Advent of code 2017/24
Ajax Direct

Answer

Part 1 :
Part 2 :
set_time_limit(0);

$graph = new Graph(function ($graph) {
    $parts = array_map(fn ($part) => explode("/", $part), explode("--", $graph->current));
    $port  = $parts[count($parts) - 1][1];

    // Unsed parts left
    $parts_left = array_filter($graph->parts, fn ($part) => !in_array($part, $parts) && !in_array(array_reverse($part), $parts));

    // Parts that can be attached to $port
    $parts_ok = array_filter($parts_left, fn ($part) => $part[0] == $port || $part[1] == $port);

    // Explore each part
    $states = [];
    foreach ($parts_ok as $part) {
        $part = [$port, $part[0] == $port ? $part[1] : $part[0]];
        $states[$graph->current . "--" . implode("/", $part)] = array_sum($part) + (!empty($graph->part2) ? 1_000_000 : 0);
    }
    return $states;
});

$graph->parts = array_map(fn ($part) => explode("/", $part), explode("\n", $input->string));

// ==================================================
// > SOLUTIONS : takes ~2 minutes
// ==================================================
$solution_1 = $graph->setTarget("highest")->explore("0/0")[1];

$graph->part2 = true; // Add 1_000_000 to the value for each step, so that we are sure it's the longest path
$solution_2 = $graph->explore("0/0")[1] % 1_000_000;