Реализация класса строк в PHP с нуля
Создание класса для работы со строками в PHP
Основное решение – класс StringHandler
Данный класс предоставляет удобный интерфейс для выполнения основных операций над строками. Он инкапсулирует строку как приватное свойство, а все методы работают с этим значением. Такой подход позволяет избежать разрозненных вызовов встроенных функций и делает код более читаемым.
class StringHandler {
private string $string;
public function __construct(string $string) {
$this->string = $string;
}
public function length(): int {
return mb_strlen($this->string, 'UTF-8');
}
public function toUpper(): self {
$this->string = mb_strtoupper($this->string, 'UTF-8');
return $this;
}
public function toLower(): self {
$this->string = mb_strtolower($this->string, 'UTF-8');
return $this;
}
public function trim(): self {
$this->string = trim($this->string);
return $this;
}
public function contains(string $needle): bool {
return mb_strpos($this->string, $needle, 0, 'UTF-8') !== false;
}
public function replace(string $search, string $replace): self {
$this->string = str_replace($search, $replace, $this->string);
return $this;
}
public function substring(int $start, ?int $length = null): self {
$this->string = mb_substr($this->string, $start, $length, 'UTF-8');
return $this;
}
public function get(): string {
return $this->string;
}
}
Пример использования:
$handler = new StringHandler(' Привет, мир! ');
echo $handler->trim()->toUpper()->substring(0, 6)->get(); // ВЫВОД: ПРИВЕТ
ПРИВЕТ
Типичные ошибки и способы их решения
- Использование
strlenвместоmb_strlen– для многобайтовых кодировок (например, UTF-8) длина считается некорректно. Решение: всегда применять мультибайтовые аналоги. - Забыли указать кодировку в функциях
mb_*– без явной передачи 'UTF-8' могут использоваться настройки сервера, что приведёт к ошибкам. Решение: всегда передавать кодировку вторым параметром. - Изменение исходной строки через методы, возвращающие новое значение – в примере выше методы изменяют внутреннее свойство и возвращают
$thisдля цепочек, но это может быть неочевидно. Решение: документировать поведение.
Вариант 1: Как сделать объект строки, который ведёт себя как простая строка?
Реализация через магический метод __toString позволяет использовать объект в строковых контекстах, а __invoke – вызывать объект как функцию для получения строки.
class MagicString {
private string $value;
public function __construct(string $value) {
$this->value = $value;
}
public function __toString(): string {
return $this->value;
}
public function __invoke(): string {
return $this->value;
}
public function upper(): string {
return mb_strtoupper($this->value, 'UTF-8');
}
}
$obj = new MagicString('hello');
echo $obj; // hello
echo $obj(); // hello
echo $obj->upper(); // HELLO
Проблема: при таком подходе каждый метод возвращает новую строку, а не изменяет объект. Это нарушает единообразие, если ожидается модификация исходного экземпляра.
Вариант 2: Как реализовать цепочку методов (fluent interface)?
Каждый метод возвращает $this, что позволяет выстраивать последовательные преобразования в одной строке без создания временных переменных.
class FluentString {
private string $str;
public function __construct(string $str) {
$this->str = $str;
}
public function append(string $suffix): self {
$this->str .= $suffix;
return $this;
}
public function prepend(string $prefix): self {
$this->str = $prefix . $this->str;
return $this;
}
public function reverse(): self {
$this->str = strrev($this->str);
return $this;
}
public function get(): string {
return $this->str;
}
}
$result = (new FluentString('мир'))->prepend('Привет, ')->append('!')->reverse()->get();
echo $result; // !рим ,тевирП
Особенность: цепочки удобны, но каждый вызов изменяет исходный объект. Если необходимо сохранить промежуточные состояния, стоит использовать неизменяемые (immutable) версии.
Вариант 3: Как работать со строками в UTF‑8 без потери символов?
Специализированный класс MbString всегда использует мультибайтовые функции и явно задаёт кодировку.
class MbString {
private string $string;
private string $encoding;
public function __construct(string $string, string $encoding = 'UTF-8') {
$this->string = $string;
$this->encoding = $encoding;
}
public function length(): int {
return mb_strlen($this->string, $this->encoding);
}
public function toLower(): self {
$this->string = mb_strtolower($this->string, $this->encoding);
return $this;
}
public function search(string $needle): int|false {
return mb_strpos($this->string, $needle, 0, $this->encoding);
}
public function get(): string {
return $this->string;
}
}
$text = new MbString('Привет, мир!');
echo $text->length(); // 12
Ошибка: без явного указания кодировки в конструкторе можно случайно обработать строку в неправильной кодировке. Рекомендуется всегда передавать кодировку.
Вариант 4: Как организовать проверку и очистку строк?
Класс-валидатор предоставляет методы для проверки email, URL, удаления HTML-тегов, фильтрации спецсимволов и т.д.
class ValidatingString {
private string $value;
public function __construct(string $value) {
$this->value = $value;
}
public function isEmail(): bool {
return filter_var($this->value, FILTER_VALIDATE_EMAIL) !== false;
}
public function stripTags(): self {
$this->value = strip_tags($this->value);
return $this;
}
public function escapeHtml(): self {
$this->value = htmlspecialchars($this->value, ENT_QUOTES, 'UTF-8');
return $this;
}
public function get(): string {
return $this->value;
}
}
$input = new ValidatingString('<script>alert(1)</script>');
echo $input->stripTags()->escapeHtml()->get(); // <script>alert(1)</script>
Назначение: защита от XSS и проверка формата ввода пользователя.
Расширенные примеры использования класса строк
Преобразование в camelCase и snake_case
class StringTransformer {
private string $str;
public function __construct(string $str) {
$this->str = $str;
}
public function toCamelCase(): string {
$parts = preg_split('/[\s_-]+/', $this->str);
$parts = array_map(fn($part) => ucfirst($part), $parts);
return lcfirst(implode('', $parts));
}
public function toSnakeCase(): string {
$result = preg_replace('/([a-z])([A-Z])/', '$1_$2', $this->str);
return mb_strtolower(preg_replace('/[\s-]+/', '_', $result), 'UTF-8');
}
public function get(): string {
return $this->str;
}
}
$t = new StringTransformer('hello world example');
echo $t->toCamelCase(); // helloWorldExample
$t2 = new StringTransformer('helloWorldExample');
echo $t2->toSnakeCase(); // hello_world_example
helloWorldExample hello_world_example
Генерация случайных строк заданной длины
class RandomStringGenerator {
private const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
public static function generate(int $length = 16): string {
$chars = self::CHARS;
$max = strlen($chars) - 1;
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= $chars[random_int(0, $max)];
}
return $result;
}
}
echo RandomStringGenerator::generate(10);
A7kL9x2Q5v
Обрезка строки до заданного количества слов
class WordTruncator {
public static function truncateWords(string $text, int $limit = 10, string $end = '...'): string {
$words = preg_split('/\s+/', trim($text));
if (count($words) <= $limit) {
return $text;
}
return implode(' ', array_slice($words, 0, $limit)) . $end;
}
}
$long = 'Один два три четыре пять шесть семь восемь девять десять одиннадцать';
echo WordTruncator::truncateWords($long, 4);
Один два три четыре...
Транслитерация кириллицы в латиницу (slug)
class Slugifier {
private static array $map = [
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
'е' => 'e', 'ё' => 'yo', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch',
'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
];
public static function toSlug(string $text): string {
$text = mb_strtolower($text, 'UTF-8');
$text = strtr($text, self::$map);
$text = preg_replace('/[^a-z0-9\s-]/', '', $text);
$text = preg_replace('/[\s]+/', '-', $text);
$text = trim($text, '-');
return $text;
}
}
echo Slugifier::toSlug('Привет, мир! Как дела?');
privet-mir-kak-dela
Подсветка совпадений в строке (highlight)
class Highlighter {
public static function highlight(string $text, string $term, string $tag = 'mark'): string {
$escaped = preg_quote($term, '/');
return preg_replace(
'/(' . $escaped . ')/iu',
'<' . $tag . ' class="fw-bold">$1' . $tag . '>',
htmlspecialchars($text, ENT_QUOTES, 'UTF-8')
);
}
}
echo Highlighter::highlight('PHP – популярный язык программирования', 'PHP');
PHP – популярный язык программирования