278 lines
8.1 KiB
PHP
278 lines
8.1 KiB
PHP
<?php
|
|
// AString.php
|
|
// Created: 2021-04-26
|
|
// Updated: 2023-07-05
|
|
|
|
namespace Index;
|
|
|
|
use Traversable;
|
|
use InvalidArgumentException;
|
|
|
|
/**
|
|
* Provides an immutable ASCII string with arrow methods.
|
|
*
|
|
* Normal PHP strings should be used for buffers/byte arrays.
|
|
*/
|
|
final class AString implements IString {
|
|
use XStringTrait;
|
|
|
|
private string $value;
|
|
|
|
/**
|
|
* Create an AString instance.
|
|
*
|
|
* @param string $value PHP string to inherit.
|
|
* @return AString New instance of AString.
|
|
*/
|
|
public function __construct(string $value) {
|
|
$this->value = $value;
|
|
}
|
|
|
|
public function getLength(): int {
|
|
return strlen($this->value);
|
|
}
|
|
|
|
public function isEmpty(): bool {
|
|
return $this->value === '';
|
|
}
|
|
|
|
public function __toString(): string {
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Checks if an offset exists in the string.
|
|
*
|
|
* You should call isset($string[$offset]) instead of $string->offsetExists($offset).
|
|
*
|
|
* @see https://www.php.net/manual/en/arrayaccess.offsetexists.php
|
|
* @param int $offset Character offset.
|
|
* @return bool true if it exists, false if not.
|
|
*/
|
|
public function offsetExists(mixed $offset): bool {
|
|
return isset($this->value[$offset]);
|
|
}
|
|
|
|
/**
|
|
* Gets an offset from the string.
|
|
*
|
|
* You should do $string[$offset] instead of $string->offsetGet($offset).
|
|
*
|
|
* @see https://www.php.net/manual/en/arrayaccess.offsetget.php
|
|
* @param int $offset Character offset.
|
|
* @return string Character at that offset.
|
|
*/
|
|
public function offsetGet(mixed $offset): mixed {
|
|
return $this->value[$offset];
|
|
}
|
|
|
|
/**
|
|
* Gets an iterator object for this string.
|
|
*
|
|
* @return StringIterator An iterator for this string.
|
|
*/
|
|
public function getIterator(): Traversable {
|
|
return new StringIterator($this);
|
|
}
|
|
|
|
/**
|
|
* Returns the data which should be serialized as json.
|
|
*
|
|
* @see https://www.php.net/manual/en/jsonserializable.jsonserialize.php
|
|
* @return mixed Data to be passed to json_encode.
|
|
*/
|
|
public function jsonSerialize(): mixed {
|
|
return $this->value;
|
|
}
|
|
|
|
public function bencodeSerialise(): mixed {
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Gets a serialized representation of this object.
|
|
*
|
|
* @return array Serialized data.
|
|
*/
|
|
public function __serialize(): array {
|
|
return [$this->value];
|
|
}
|
|
|
|
/**
|
|
* Reconstructs an object from a serialized string.
|
|
*
|
|
* @param array $serialized Serialized data.
|
|
*/
|
|
public function __unserialize(array $serialized): void {
|
|
$this->value = $serialized[0];
|
|
}
|
|
|
|
/**
|
|
* Checks whether this string is identical to another.
|
|
*
|
|
* @param mixed $other An instance of AString or a PHP string.
|
|
* @return bool true if the strings have the same value, false if not.
|
|
*/
|
|
public function equals(mixed $other): bool {
|
|
return $this->compare($other) === 0;
|
|
}
|
|
|
|
/**
|
|
* Compares whether this string is identical to another.
|
|
*
|
|
* @param mixed $other An instance of IString or a PHP string.
|
|
*/
|
|
public function compare(mixed $other): int {
|
|
return strcmp($this->value, (string)$other);
|
|
}
|
|
|
|
/**
|
|
* Creates a new identical AString instance.
|
|
*
|
|
* This method is somewhat pointless, given the immutable nature of this object,
|
|
* but rather people calling this instead of calling ->substring(0);
|
|
*
|
|
* @return AString A new identical instance of AString.
|
|
*/
|
|
public function clone(): mixed {
|
|
return new AString($this->value);
|
|
}
|
|
|
|
public function indexOf(IString|string $text, int $offset = 0): int {
|
|
$pos = strpos($this->value, (string)$text, $offset);
|
|
if($pos === false)
|
|
return -1;
|
|
return $pos;
|
|
}
|
|
|
|
public function contains(IString|string $text): bool {
|
|
return str_contains($this->value, (string)$text);
|
|
}
|
|
|
|
public function substring(int $offset, int|null $length = null): IString {
|
|
return new AString(substr($this->value, $offset, $length));
|
|
}
|
|
|
|
public function replace(IString|string $search, IString|string $replace): IString {
|
|
return new AString(str_replace((string)$search, (string)$replace, $this->value));
|
|
}
|
|
|
|
public function append(IString|string $string): IString {
|
|
return new AString($this->value . (string)$string);
|
|
}
|
|
|
|
public function prepend(IString|string $string): IString {
|
|
return new AString(((string)$string) . $this->value);
|
|
}
|
|
|
|
public function split(IString|string $separator, int $limit = PHP_INT_MAX): array {
|
|
$separator = (string)$separator;
|
|
if(empty($separator))
|
|
throw new InvalidArgumentException('$separator may not be empty.');
|
|
return XArray::select(
|
|
explode($separator, $this->value, $limit),
|
|
fn($str) => new AString($str)
|
|
);
|
|
}
|
|
|
|
public function chunk(int $chunkSize): array {
|
|
return XArray::select(
|
|
str_split($this->value, $chunkSize),
|
|
fn($str) => new AString($str)
|
|
);
|
|
}
|
|
|
|
public function trim(IString|string $characters = IString::TRIM_CHARS): IString {
|
|
return new AString(trim($this->value, (string)$characters));
|
|
}
|
|
|
|
public function trimStart(IString|string $characters = IString::TRIM_CHARS): IString {
|
|
return new AString(ltrim($this->value, (string)$characters));
|
|
}
|
|
|
|
public function trimEnd(IString|string $characters = IString::TRIM_CHARS): IString {
|
|
return new AString(rtrim($this->value, (string)$characters));
|
|
}
|
|
|
|
public function toLower(): IString {
|
|
return new AString(strtolower($this->value));
|
|
}
|
|
|
|
public function toUpper(): IString {
|
|
return new AString(strtoupper($this->value));
|
|
}
|
|
|
|
public function reverse(): IString {
|
|
return new AString(strrev($this->value));
|
|
}
|
|
|
|
public function countUnique(): int {
|
|
return XString::countUnique($this->value);
|
|
}
|
|
|
|
public function startsWith(IString|string $text): bool {
|
|
return str_starts_with($this->value, (string)$text);
|
|
}
|
|
|
|
public function endsWith(IString|string $text): bool {
|
|
return str_ends_with($this->value, (string)$text);
|
|
}
|
|
|
|
/**
|
|
* Casts this AString to a WString.
|
|
*
|
|
* @param ?string $encoding Intended encoding, null for the Index-level default.
|
|
* @param bool $convert true to convert the string to the target encoding, false to leave the bytes as-is.
|
|
* @return WString A WString of the provided encoding with the value of this AString.
|
|
*/
|
|
public function toWString(?string $encoding = null, bool $convert = true): WString {
|
|
$value = $this->value;
|
|
$encoding ??= WString::getDefaultEncoding();
|
|
if($convert)
|
|
$value = mb_convert_encoding($value, $encoding, 'ascii');
|
|
return new WString($value, $encoding);
|
|
}
|
|
|
|
/**
|
|
* Joins an iterable object together with a separator to create a string.
|
|
*
|
|
* @param iterable $source Source object.
|
|
* @param IString|string $separator Separator to use as glue.
|
|
* @return AString Resulting string.
|
|
*/
|
|
public static function join(iterable $source, IString|string $separator = ''): AString {
|
|
if(!is_array($source)) {
|
|
$parts = [];
|
|
foreach($source as $value)
|
|
$parts[] = $value;
|
|
$source = $parts;
|
|
}
|
|
|
|
return new AString(implode((string)$separator, $source));
|
|
}
|
|
|
|
/**
|
|
* Returns a reusable empty string instance.
|
|
*
|
|
* @return AString An empty string.
|
|
*/
|
|
public static function empty(): AString {
|
|
static $empty = null;
|
|
$empty ??= new AString('');
|
|
return $empty;
|
|
}
|
|
|
|
/**
|
|
* Converts a value to AString.
|
|
*
|
|
* @param mixed $value Source value.
|
|
* @return AString An AString representing the given value.
|
|
*/
|
|
public static function cast(mixed $value): AString {
|
|
if($value instanceof AString)
|
|
return $value;
|
|
if($value instanceof WString)
|
|
return $value->toAString();
|
|
return new AString((string)$value);
|
|
}
|
|
}
|