Advent of code 2020/18
Ajax Direct

Answer

Part 1 :
Part 2 :
function solve($ops, $reading_order = false) {
    global $input;

    // Create a function that calculates based on the defined order
    $calc = function ($expr) use ($ops, $reading_order) {
        foreach ($ops as $op) {
            while (preg_match("/".$op."/", $expr)) {
                $expr = preg_replace_callback("/".($reading_order?"^":"")."([0-9]+) (".$op.") ([0-9]+)/", fn ($p) =>
                    $p[2] == "+"
                        ? $p[1] + $p[3]
                        : $p[1] * $p[3]
                , $expr);
            }
        }
        return $expr;
    };

    // Replace parenthesis with result until there is none, then calculate what's left
    return $input->lines->map(function ($line) use ($calc) {
        while ($p = $line->match("/\(([^)(]+)\)/")) {
            $line = $line->replace($p[0], $calc($p[1]));
        }

        return $calc($line);
    })->sum();
}

$solution_1 = solve(["(?:\+|\*)"], true);
$solution_2 = solve(["\+", "\*"], false);