expires_at = $expires_at; $this->clock = $clock; $this->budget_seconds = $budget_seconds; } /** * Builds a deadline from PHP's execution limit. * * @since 1.14.0 * * @param callable|null $clock Optional. Defaults to microtime. * @param int|null $php_limit Optional. Defaults to ini max_execution_time. * * @return self */ public static function from_php_limit( ?callable $clock = null, ?int $php_limit = null ): self { $clock = $clock ?? static fn(): float => microtime( true ); if ( null === $php_limit ) { $php_limit = (int) ini_get( 'max_execution_time' ); } // 0 means unlimited; an absurdly long limit is treated the same way, // because a batch measured in minutes is indistinguishable from a hang // to the person watching the progress bar. $limit = ( $php_limit <= 0 || $php_limit > self::SELF_CAP_SECONDS ) ? self::SELF_CAP_SECONDS : $php_limit; $budget = max( self::MIN_BUDGET_SECONDS, $limit - self::SAFETY_PAD_SECONDS ); /** * Filters the per-batch time budget in seconds. * * @since 1.14.0 * * @param int $budget Seconds of work allowed in one batch. */ $budget = (int) apply_filters( 'postlinkly_index_batch_budget', $budget ); $budget = max( self::MIN_BUDGET_SECONDS, $budget ); return new self( $clock() + $budget, $clock, $budget ); } /** * Whether the batch has run out of time. * * @since 1.14.0 */ public function expired(): bool { return ( $this->clock )() >= $this->expires_at; } /** * Seconds left before the batch must stop; never negative. * * @since 1.14.0 */ public function remaining(): float { return max( 0.0, $this->expires_at - ( $this->clock )() ); } /** * Seconds of work this deadline allows in total. * * @since 1.14.0 */ public function budget_seconds(): int { return $this->budget_seconds; } }