self::OPTION, 'compute' => static function (?string $stored) use ($version, &$unreadable): ?string { $unreadable = null; if ($stored === null || $stored === '') { return $version; } if (preg_match(self::VERSION_PATTERN, $stored) !== 1) { $unreadable = $stored; return $version; } return version_compare($stored, $version, '<') ? $version : null; }, )); // Report a repair only after its conditional write succeeded. A lost // race may instead reveal a valid newer record, which must survive. if ($result === ABJ_404_Solution_OptionRowCompareAndSwap::RESULT_SWAPPED && $unreadable !== null) { abj_service('logging')->warn("The schema high-water record (option " . self::OPTION . ") held an unreadable value (\"" . $unreadable . "\"); replaced it with " . $version . "."); } } /** * Whether a newer version than the given one has already shaped the schema. * An empty or missing record never blocks: a site that never ran a build * writing the record has no evidence of a newer schema. An unreadable record * always blocks, because a newer build may have written it. * * @param string $version The running plugin version. * @return bool True when the record is unreadable, or exists and is newer than $version. */ public static function isNewerThan(string $version): bool { $recorded = self::read(); if ($recorded === null) { return true; } return $recorded !== '' && version_compare($version, $recorded, '<'); } }