diff --git a/composer.json b/composer.json index 5619aac8d5c..7e115a36652 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "symfony/config": "^3.2 || ^4", "symfony/translation": "^2.8 || ^3 || ^4", "symfony/yaml": "^3.2 || ^4", - "php": "^7.3 || ^8", + "php": "^7.4 || ^8.0", "ext-ctype": "*", "ext-dom": "*", "ext-hash": "*", diff --git a/src/Control/ContentNegotiator.php b/src/Control/ContentNegotiator.php index fa8c8ff5a51..b64add40b2a 100644 --- a/src/Control/ContentNegotiator.php +++ b/src/Control/ContentNegotiator.php @@ -88,7 +88,7 @@ public static function enabled_for($response) if (ContentNegotiator::getEnabled()) { return true; } else { - return (substr($response->getBody(), 0, 5) == '<' . '?xml'); + return (substr($response->getBody() ?: '', 0, 5) == '<' . '?xml'); } } diff --git a/src/Control/HTTPRequest.php b/src/Control/HTTPRequest.php index d6ac4e026da..7dc929dde89 100644 --- a/src/Control/HTTPRequest.php +++ b/src/Control/HTTPRequest.php @@ -434,7 +434,7 @@ public function isAjax() * @param string $offset * @return bool */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->postVars[$offset]) || isset($this->getVars[$offset]); } @@ -445,17 +445,19 @@ public function offsetExists($offset) * @param string $offset * @return mixed */ + # Remove this attribute when PHP 8.0 is the minimum version and set method return type to mixed + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->requestVar($offset); } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { $this->getVars[$offset] = $value; } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->getVars[$offset]); unset($this->postVars[$offset]); diff --git a/src/Core/Convert.php b/src/Core/Convert.php index db8f14bc438..e769e7d53f8 100644 --- a/src/Core/Convert.php +++ b/src/Core/Convert.php @@ -131,7 +131,7 @@ public static function raw2xml($val) return $val; } - return htmlspecialchars($val, ENT_QUOTES, 'UTF-8'); + return htmlspecialchars($val ?: '', ENT_QUOTES, 'UTF-8'); } /** diff --git a/src/Core/Injector/Injector.php b/src/Core/Injector/Injector.php index 7dcfea32434..4cac44fc13b 100644 --- a/src/Core/Injector/Injector.php +++ b/src/Core/Injector/Injector.php @@ -419,7 +419,7 @@ public function load($config = []) } // okay, actually include it now we know we're going to use it - if (file_exists($file)) { + if ($file && file_exists($file)) { require_once $file; } @@ -524,7 +524,7 @@ public function convertServiceProperty($value) } // Evaluate constants surrounded by back ticks - if (preg_match('/^`(?[^`]+)`$/', $value, $matches)) { + if (preg_match('/^`(?[^`]+)`$/', $value ?: '', $matches)) { $envValue = Environment::getEnv($matches['name']); if ($envValue !== false) { $value = $envValue; diff --git a/src/Core/Manifest/ManifestFileFinder.php b/src/Core/Manifest/ManifestFileFinder.php index 46fa5ea0947..d55fd73d625 100644 --- a/src/Core/Manifest/ManifestFileFinder.php +++ b/src/Core/Manifest/ManifestFileFinder.php @@ -208,7 +208,7 @@ public function isDirectoryModule($basename, $pathname, $depth) protected function upLevels($pathname, $depth) { if ($depth < 0) { - return null; + return ''; } while ($depth--) { $pathname = dirname($pathname); diff --git a/src/Core/Manifest/Module.php b/src/Core/Manifest/Module.php index 23a974fb3a0..e9f1c16be50 100644 --- a/src/Core/Manifest/Module.php +++ b/src/Core/Manifest/Module.php @@ -6,7 +6,6 @@ use Exception; use InvalidArgumentException; use RuntimeException; -use Serializable; use SilverStripe\Core\Path; use SilverStripe\Dev\Deprecation; @@ -14,7 +13,7 @@ * Abstraction of a PHP Package. Can be used to retrieve information about Silverstripe CMS modules, and other packages * managed via composer, by reading their `composer.json` file. */ -class Module implements Serializable +class Module { /** * @deprecated 4.1.0:5.0.0 Use Path::normalise() instead @@ -185,11 +184,42 @@ public function getRelativePath() return substr($this->path, strlen($this->basePath) + 1); } + public function __serialize(): array + { + return [ + 'path' => $this->path, + 'basePath' => $this->basePath, + 'composerData' => $this->composerData + ]; + } + + public function __unserialize(array $data): void + { + $this->path = $data['path']; + $this->basePath = $data['basePath']; + $this->composerData = $data['composerData']; + $this->resources = []; + } + + /** + * The __serialize() magic method will be automatically used instead of this + * + * @return string + * @deprecated will be removed in 5.0 + */ public function serialize() { return json_encode([$this->path, $this->basePath, $this->composerData]); } + /** + * The __unserialize() magic method will be automatically used instead of this almost all the time + * This method will be automatically used if existing serialized data was not saved as an associative array + * and the PHP version used in less than PHP 9.0 + * + * @param string $serialized + * @deprecated will be removed in 5.0 + */ public function unserialize($serialized) { list($this->path, $this->basePath, $this->composerData) = json_decode($serialized, true); diff --git a/src/ORM/ValidationResult.php b/src/ORM/ValidationResult.php index e839387d1db..5f852131db2 100644 --- a/src/ORM/ValidationResult.php +++ b/src/ORM/ValidationResult.php @@ -214,10 +214,25 @@ public function combineAnd(ValidationResult $other) return $this; } + public function __serialize(): array + { + return [ + 'messages' => $this->messages, + 'isValid' => $this->isValid() + ]; + } + + public function __unserialize(array $data): void + { + $this->messages = $data['messages']; + $this->isValid = $data['isValid']; + } + /** - * String representation of object + * The __serialize() magic method will be automatically used instead of this * - * @return string the string representation of the object or null + * @return string + * @deprecated will be removed in 5.0 */ public function serialize() { @@ -225,9 +240,12 @@ public function serialize() } /** - * Constructs the object + * The __unserialize() magic method will be automatically used instead of this almost all the time + * This method will be automatically used if existing serialized data was not saved as an associative array + * and the PHP version used in less than PHP 9.0 * * @param string $serialized + * @deprecated will be removed in 5.0 */ public function unserialize($serialized) { diff --git a/src/i18n/Messages/Symfony/FlushInvalidatedResource.php b/src/i18n/Messages/Symfony/FlushInvalidatedResource.php index 0e01f45f1fb..72b4487a17d 100644 --- a/src/i18n/Messages/Symfony/FlushInvalidatedResource.php +++ b/src/i18n/Messages/Symfony/FlushInvalidatedResource.php @@ -40,11 +40,35 @@ public function isFresh($timestamp) return false; } + public function __serialize(): array + { + return []; + } + + public function __unserialize(array $data): void + { + // no-op + } + + /** + * The __serialize() magic method will be automatically used instead of this + * + * @return string + * @deprecated will be removed in 5.0 + */ public function serialize() { return ''; } + /** + * The __unserialize() magic method will be automatically used instead of this almost all the time + * This method will be automatically used if existing serialized data was not saved as an associative array + * and the PHP version used in less than PHP 9.0 + * + * @param string $serialized + * @deprecated will be removed in 5.0 + */ public function unserialize($serialized) { // no-op diff --git a/src/includes/constants.php b/src/includes/constants.php index cbba29d00cd..933842b00d3 100644 --- a/src/includes/constants.php +++ b/src/includes/constants.php @@ -111,7 +111,7 @@ $base = Environment::getEnv('SS_BASE_URL'); if ($base) { // Strip relative path from SS_BASE_URL - return rtrim(parse_url($base, PHP_URL_PATH), '/'); + return rtrim(parse_url($base, PHP_URL_PATH) ?: '', '/'); } // Unless specified, use empty string for base in CLI