From 6e831e2650b3b3df56a4b5a9b103aa1bf25f1c78 Mon Sep 17 00:00:00 2001 From: babaev-an Date: Mon, 7 Jul 2025 18:02:04 +0300 Subject: [PATCH] 20250707 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Бета 1.1.1 --- sources/operators/JsonReWriter.md | 710 +++++++++++++++++++++++++++++ sources/operators/Operators.php | 46 ++ sources/types/BoolEx.php | 119 +++++ sources/types/JsonReWriter.md | 710 +++++++++++++++++++++++++++++ tests/classes/JsonReWriterTest.php | 32 +- 5 files changed, 1601 insertions(+), 16 deletions(-) create mode 100644 sources/operators/JsonReWriter.md create mode 100644 sources/operators/Operators.php create mode 100644 sources/types/BoolEx.php create mode 100644 sources/types/JsonReWriter.md diff --git a/sources/operators/JsonReWriter.md b/sources/operators/JsonReWriter.md new file mode 100644 index 0000000..0263fa8 --- /dev/null +++ b/sources/operators/JsonReWriter.md @@ -0,0 +1,710 @@ +# Описание класса JsonReWriter + +## Информация о версии + +Версия класса: 1.0 + +Впервые введено в пакет с версии: 1.1.0 + +Описание класса: Класс для работы с JSON-файлами. + +## Публичные свойства и константы класса + +В классе определены следующие свойства: + +- `string $JsonString` - строка JSON (чтение/запись). + +## Быстрый старт + +### Правила формирования ключей. + +Ключ для чтения/записи данных класса формируется следующим образом: `ключ/подключ/подключ подключа` . + +Например, если дан json-файл: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +Пусть требуется получить значение `BBB`, тогда ключ должен быть `test/subtest/BBB`. + +### Чтение. + +1. Создайте элемент класса `$json = new JsonReWriter ();` +2. Если у вас требуется загрузить json из файла `$fileName`, то воспользуйтесь методом `LoadFromFile`: + `$json->LoadFromFile($fileName);`, если же json представлен строкой `$jsonStr`, то загрузите её в свойство + `$JsonString`: `$json->JsonString = $jsonStr;` +3. Далее можно пользоваться любым методом для чтения `Read*`, в том числе и общим `$json->Read(...)`. + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаю класс + $json = new JsonReWriter(); + // Загшружаю данные из файла + $json->LoadFromFile($fileName); + // Получаю число + $float = $json->ReadFloat("test/subtest/BBB", 0.2); + +В итоге в `$float` будет `1.23`. + +### Запись. + +1. Создайте элемент класса `$json = new JsonReWriter ();` +2. Далее можно пользоваться любым методом для записи `Write*`, в том числе и общим `$json->Write(...)`. +3. Если вам требуется создать json файл с именем `$fileName`, то воспользуйтесь методом `SaveToFile`: + `$json->SaveToFile($fileName);`, если же json должен быть представлен строкой `$jsonStr`, то загрузите её из свойства + `$JsonString`: `$jsonStr = $json->JsonString;` + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаю класс + $json = new JsonReWriter(); + // Загшружаю данные из файла + $json->LoadFromFile($fileName); + // Получаю число + try { + $json->Write("test/subtest/BBB", 0.2); + } + catch (JsonException $e) { + echo $e->getMessage(); + } + +В итоге в `test/subtest/BBB` вместо `1.23` будет `0.2`. + +## Коды ошибок JsonErrorCode + +Ниже представлена таблица основных кодов ошибки: + +| Ошибка | Описание | Введено с версии | +|:-------------------:|:---------------------------------------------------------------------------:|:----------------:| +| Unknown | Неизвестная ошибка | 1.0 | +| None | Ошибок нет | 1.0 | +| Depth | Достигнута максимальная глубина стека | 1.0 | +| StateMismatch | Неверный или некорректный JSON | 1.0 | +| CTRLChar | Ошибка управляющего символа, возможно, неверная кодировка | 1.0 | +| Syntax | Синтаксическая ошибка | 1.0 | +| UTF8 | Некорректные для кодировки UTF-8 символы, возможно, неверная кодировка | 1.0 | +| Recursion | Одна или несколько зацикленных ссылок в кодируемом значении | 1.0 | +| InfOrNan | Одно или несколько значений NAN или INF в кодируемом значении | 1.0 | +| UnsupportedType | Передали значение с неподдерживаемым типом | 1.0 | +| InvalidPropertyName | Имя свойства не может быть закодировано | 1.0 | +| UTF16 | Некорректный для кодировки UTF-16 символ, возможно, некорректно закодирован | 1.0 | +| KeyIsNotArray | Ключ не содержит вложений, хотя от него требуется обратное | 1.0 | +| NotISerializable | Класс не реализует интерфейс ISerializable | 1.0 | + +### Методы и функции перечисления JsonErrorCode + +Перечисление содержит **статический метод** `static function FromLastError (): JsonErrorCode`, который получает код +ошибки из последней JSON ошибки. + +Например, при успешной загрузке, можем проверить ошибки: + + $errors = JsonErrorCode::FromLastError (); + +После того, как мы выведем `$errors`, мы получим `JsonErrorCode::None`. + +## Исключение JsonException + +Исключение расширяет класс `Exception`, поэтому может выбрасываться через `throw`. + +### Свойства + +Исключение содержит следующие свойства: + +- `?string $JsonString` - строка JSON (или null); +- `JsonErrorCode $ErrorCode` - код ошибки JSON; +- `?string $ErrorMessage` - сообщение об ошибке JSON (в отличие от функции json_last_error_msg(), данная переменная при + отсутствии ошибок выводит null, а не "No error"). + +### Методы и функции + +#### Конструктор. + +Конструктор принимает **3 необязательных параметра**: + +* `?string $json` - строка JSON (по умолчанию, `null`); +* `JsonErrorCode $errorCode` - код ошибки (по умолчанию, `JsonErrorCode::Unknown`); +* `?string $errorMessage` - сообщение об ошибке (по умолчанию, `null`). + +В результате создаётся новое исключение `JsonException`. + +Пример: + + throw new JsonException("{}", JsonErrorCode::Depth, "Пример"); + +Создаст исключение `JsonException`. + +## Методы и функции + +### Конструктор и деструктор. + +Конструктор не принимает никаких параметров. + +В результате создаётся новый класс `JsonReWriter`. + +**Пример:** + + // Контсуктор + $json = new JsonReWriter (); + // Деструктор + unset($json); + +Создаст и уничтожит класс `JsonReWriter`. + +### Сохранение и загрузка из файла. + +За сохранение и загрузку отвечают 2 метода: `SaveToFile` и `LoadFromFile`. + +#### Сохранение в файл (метод `SaveToFile`) + +Этот метод сохраняет содержимое JSON в файл. Он содержит **1 обязательный параметр**: + +* `string $fileName` - имя файла на диске. + +Метод возвращает `bool` - сохранены ли данные в файл: `true` - да, `false` - нет. + +Синтаксис: + + public function SaveToFile (string $fileName): bool + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Сохраняем созданный JSON файл + $json->SaveToFile($fileName); + +Содержимое файла `test.json` представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +#### Загрузка файла (метод `LoadFromFile`) + +Этот метод загружает содержимое файла в класс. Он содержит **1 обязательный параметр**: + +* `string $fileName` - имя файла на диске. + +Метод возвращает `bool` - загружены ли данные из файла: `true` - да, `false` - нет. + +Синтаксис: + + public function LoadFromFile (string $fileName): bool + +**Пример:** +Пусть дан файл `test.json`, содержимое которого представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +Следующий код загрузит это содержимое в класс: + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Загружаю данные + $json->LoadFromFile($fileName); + +### Чтение данных + +Для чтения данных используется один общий метод `Read` и 7 его производных метода: `ReadString`, `ReadInt`, `ReadFloat`, +`ReadBool`, `ReadArray`, `ReadObject` и `ReadSerializable`. + +#### Метод `Read` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `mixed $default` (значение по умолчанию, задан по умолчанию в `null`). + +Этот метод возвращает `mixed`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function Read (string $key, mixed $default = null): mixed + +**Пример,** + + // Создаю класс + $json = new JsonReWriter(); + // Заполняю данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->Write("test3/test/res", json_encode([1, 2, 3])); + } catch (JsonException $e) { + echo $e->getMessage(); + } + + // Получаю значение + $float = (float)$json->Read("test/subtest/BBB")); + +В результате, переменная `$float` будет иметь значение `1.23`. + +#### Метод `ReadString` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `string $default` (значение по умолчанию, задан по умолчанию в `""`). + +Этот метод возвращает `string`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadString (string $key, string $default = ""): string + +#### Метод `ReadInt` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `int $default` (значение по умолчанию, задан по умолчанию в `0`). + +Этот метод возвращает `int`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadInt (string $key, int $default = 0): int + +#### Метод `ReadFloat` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `float $default` (значение по умолчанию, задан по умолчанию в `0.0`). + +Этот метод возвращает `float`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadFloat (string $key, float $default = 0.0): float + +#### Метод `ReadBool` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `bool $default` (значение по умолчанию, задан по умолчанию в `false`). + +Этот метод возвращает `bool`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadBool (string $key, bool $default = false): bool + +#### Метод `ReadArray` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `array $default` (значение по умолчанию, задан по умолчанию в `[]`). + +Этот метод возвращает `array`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadArray (string $key, array $default = []): array + +#### Метод `ReadObject` + +Это метод, который читает значение ключа JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `object $default` (значение по умолчанию). + +Этот метод возвращает `object`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadObject (string $key, object $default): object + +#### Метод `ReadSerializable` + +Это метод, который читает значение ключа JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `string $serializableClassName` (имя класса, реализующего интерфейс ISerializable, с namespace). + +Этот метод возвращает класс, реализующий интерфейс `ISerializable`. + +**Важно!** Этот метод может выбросить исключение `JsonException`, если класс, заданный в `$serializableClassName` не +реализует интерфейс `ISerializable`. + +Синтаксис: + + public function ReadSerializable (string $key, string $serializableClassName): ISerializable + +**Пример,** + +Пусть для примера, класс `Demo` из namespace `iam\namespace` реализует интерфейс `ISerializable`. + + // Создаю класс + $json = new JsonReWriter(); + // ... Здесь где-то загрузка данных + // Получаю класс + try { + /** + * @var Demo $unSerializableClass + */ + $unSerializableClass = $json->ReadSerializable("test", "iam\\namespace\\Demo"); + } catch (JsonException $e) { + echo $e->getMessage(); + } + +В результате, переменная `$unSerializableClass` будет содержать данные класса `Demo`. + +### Запись данных + +Для чтения данных используется один общий метод `Write` и 3 его производных метода: `WriteArray`, `WriteObject` и +`WriteSerializable`. + +**Важно!** Лобой из вышеуказанных методов может выбросить исключение `JsonException`, если ключ не содержит вложений, +хотя от него требуется обратное. + +#### Метод `Write` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `mixed $value` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function Write (string $key, mixed $value): void + +**Пример,** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Сохраняем созданный JSON файл + $json->SaveToFile($fileName); + +Содержимое файла `test.json` представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +#### Метод `WriteArray` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `array $array` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteArray (string $key, array $array): void + +#### Метод `WriteObject` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `object $value` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteObject (string $key, object $value): void + +#### Метод `WriteSerializable` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `ISerializable $serializableValue` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteSerializable (string $key, ISerializable $serializableValue): void + +**Пример,** +Пусть для примера, класс `Demo` из namespace `iam\namespace` реализует интерфейс `ISerializable`. + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Создаём класс Demo + $serializableClass = new Demo(...); + // Заполним данными + try { + $json->WriteSerializable("test", $serializableClass); + } catch (JsonException $e) { + echo $e->getMessage(); + } + ... + +### Работа с ключами JSON + +Для работы с ключами JSON есть 2 метода: `IsKeyExists` и `GetKeys`. + +#### Метод `IsKeyExists` + +Это метод проверяем наличие ключа в JSON. Он имеет **1 обязательный параметр** - `string $key` (ключ). + +Этот метод возвращает `bool`: `true` если ключ найден и `false` в противном случае. + +Синтаксис: + + public function IsKeyExists (string $key): bool + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Проверяем ключи + $check1 = $json->IsKeyExists("test/subtest/AAA"); + $check2 = $json->IsKeyExists("test/subtest/ССС"); + +В результате, `$check1` будет `true`, а `$check2` - `false`. + +#### Метод `GetKeys` + +Это метод получает список ключей. Он имеет **2 необязательных параметра**: + +- `string $parentKey` (ключ родителя (или "" (установлено по умолчанию) для всех); +- `bool $includeChildren` (нужно ли включать дочерние ключи (по умолчанию, да)). + +Этот метод возвращает `array`: список ключей. + +Синтаксис: + + public function GetKeys (string $parentKey = "", bool $includeChildren = true): array + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Получаем ключи + $keys1 = $json->GetKeys("test"); + $keys2 = $json->GetKeys("test", false); + $keys3 = $json->GetKeys(); + +В результате, `$key1` будет следующим массивом: + + [ + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB" + ] + +`$key2` будет следующим массивом: + + [ + "subtest" + ] + +`$key3` будет следующим массивом: + + [ + "test", + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB", + "test1", + "test1/test", + "test2", + "test2/test", + "test3", + "test3/test", + "test3/test/res" + ] + +### Удаление ключей JSON + +Для удаления ключей JSON есть 2 метода: `DeleteKey`, который удаляет только определённый ключ и `Clear`, который удаляет +**все ключи** из json-файла. + +#### Метод `DeleteKey` + +Это метод удаляет только определённый ключ в JSON. Он имеет **1 обязательный параметр** - `string $key` (ключ). + +Этот метод возвращает `bool` - результат удаления ключа: `true` - удаление прошло успешно, `false` - произошла ошибка +при удалении. + +Синтаксис: + + public function DeleteKey (string $key): bool + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Получаемем ключи до удаления + $check1 = $json->GetKeys("test/subtest"); + // Удаляем ключ + $this->DeleteKey("test/subtest/BBB"); + // Получаемем ключи после удаления + $check2 = $json->GetKeys("test/subtest"); + +В результате, `$check1` будет + + [ + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB" + ] + +а `$check2`: + + [ + "test/subtest", + "test/subtest/AAA" + ] + +#### Метод `Clear` + +Это метод удаляет **все ключи** из json-файла. Он не имеет никаких параметров и ничего не возвращает. + +Синтаксис: + + public function Clear (): void + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Очищаем + $json->Clear(); + // Получаем ключи + $keys = $json->GetKeys(); + +В результате, `$key` будет следующим массивом: + + [ + ] \ No newline at end of file diff --git a/sources/operators/Operators.php b/sources/operators/Operators.php new file mode 100644 index 0000000..c2187c7 --- /dev/null +++ b/sources/operators/Operators.php @@ -0,0 +1,46 @@ +$value равно одному из значений $values. + * + * @param mixed $value Искомое значение. + * @param mixed ...$values Массив значений. + * + * @return bool Возвращает true, если значение $value равно одному из значений + * $values, иначе false. + */ + public static function Is (mixed $value, mixed ...$values): bool + { + // Проверяем, что хотя бы одно из значений равно искомому и возвращаем результат + return array_any($values, fn ($curValue) => $curValue === $value); + } + + /** + * Проверяет, сколько раз значение $value встречается в массиве $values. + * + * @param mixed $value Искомое значение. + * @param mixed ...$values Массив значений. + * + * @return int Возвращает количество значений $values, которые равны $value. + */ + public static function IsCount (mixed $value, mixed ...$values): int + { + // Получаем массив значений повторений + $result = array_count_values($values); + + // Возвращаем результат + return $result[$value] ?? 0; + } +} \ No newline at end of file diff --git a/sources/types/BoolEx.php b/sources/types/BoolEx.php new file mode 100644 index 0000000..66ecc3f --- /dev/null +++ b/sources/types/BoolEx.php @@ -0,0 +1,119 @@ +Value = $value === null ? self::Null : ($value ? self::True : self::False); + } + + /** + * Преобразует значение в экземпляр типа. + * + * ВАЖНО: при преобразовании в тип будет использована следующая логика: + * + * - 'true', '1', 'on', 'yes', 'y', + * 't', true, 1, 1.0 считаются как истина; + * - 'false', '0', 'off', 'no', 'n', + * 'f', false, -1, -1.0 считаются как ложь; + * - все остальные значения считаются как неустановленною (и не истина, и не ложь). + * + * @param mixed $value Значение. + * + * @return BoolEx Возвращает экземпляр типа. + */ + public static function Parse (mixed $value): BoolEx + { + // Преобразуем значение в тип + $value = match ($value) { + 'true', '1', 'on', 'yes', 'y', 't', true, 1, 1.0 => self::True, + 'false', '0', 'off', 'no', 'n', 'f', false, -1, -1.0 => self::False, + default => self::Null + }; + + // Создаем экземпляр типа + return new BoolEx($value); + } + + /** + * Проверяет, является ли значение ложью. + * + * @return bool Возвращает, является ли значение ложью. + */ + public function IsFalse (): bool + { + return $this->Value === self::False; + } + + /** + * Проверяет, является ли значение истиной. + * + * @return bool Возвращает, является ли значение истиной. + */ + public function IsTrue (): bool + { + return $this->Value === self::True; + } + + /** + * Возвращает строковое представление значения. + * + * @return string Возвращает строковое представление значения. + */ + public function __toString (): string + { + // Преобразуем значение в строку + return match ($this->Value) { + self::True => "true", + self::False => "false", + self::Null => "null" + }; + } + + /** + * Конвертирует значение в bool. + * + * @param bool $onNull Значение, возвращаемое при неустановленном значении. + * + * @return bool Возвращает значение, конвертированное в bool. + */ + public function AsBool (bool $onNull = false): bool + { + return match ($this->Value) { + self::True => true, + self::False => false, + default => $onNull + }; + } +} \ No newline at end of file diff --git a/sources/types/JsonReWriter.md b/sources/types/JsonReWriter.md new file mode 100644 index 0000000..0263fa8 --- /dev/null +++ b/sources/types/JsonReWriter.md @@ -0,0 +1,710 @@ +# Описание класса JsonReWriter + +## Информация о версии + +Версия класса: 1.0 + +Впервые введено в пакет с версии: 1.1.0 + +Описание класса: Класс для работы с JSON-файлами. + +## Публичные свойства и константы класса + +В классе определены следующие свойства: + +- `string $JsonString` - строка JSON (чтение/запись). + +## Быстрый старт + +### Правила формирования ключей. + +Ключ для чтения/записи данных класса формируется следующим образом: `ключ/подключ/подключ подключа` . + +Например, если дан json-файл: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +Пусть требуется получить значение `BBB`, тогда ключ должен быть `test/subtest/BBB`. + +### Чтение. + +1. Создайте элемент класса `$json = new JsonReWriter ();` +2. Если у вас требуется загрузить json из файла `$fileName`, то воспользуйтесь методом `LoadFromFile`: + `$json->LoadFromFile($fileName);`, если же json представлен строкой `$jsonStr`, то загрузите её в свойство + `$JsonString`: `$json->JsonString = $jsonStr;` +3. Далее можно пользоваться любым методом для чтения `Read*`, в том числе и общим `$json->Read(...)`. + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаю класс + $json = new JsonReWriter(); + // Загшружаю данные из файла + $json->LoadFromFile($fileName); + // Получаю число + $float = $json->ReadFloat("test/subtest/BBB", 0.2); + +В итоге в `$float` будет `1.23`. + +### Запись. + +1. Создайте элемент класса `$json = new JsonReWriter ();` +2. Далее можно пользоваться любым методом для записи `Write*`, в том числе и общим `$json->Write(...)`. +3. Если вам требуется создать json файл с именем `$fileName`, то воспользуйтесь методом `SaveToFile`: + `$json->SaveToFile($fileName);`, если же json должен быть представлен строкой `$jsonStr`, то загрузите её из свойства + `$JsonString`: `$jsonStr = $json->JsonString;` + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаю класс + $json = new JsonReWriter(); + // Загшружаю данные из файла + $json->LoadFromFile($fileName); + // Получаю число + try { + $json->Write("test/subtest/BBB", 0.2); + } + catch (JsonException $e) { + echo $e->getMessage(); + } + +В итоге в `test/subtest/BBB` вместо `1.23` будет `0.2`. + +## Коды ошибок JsonErrorCode + +Ниже представлена таблица основных кодов ошибки: + +| Ошибка | Описание | Введено с версии | +|:-------------------:|:---------------------------------------------------------------------------:|:----------------:| +| Unknown | Неизвестная ошибка | 1.0 | +| None | Ошибок нет | 1.0 | +| Depth | Достигнута максимальная глубина стека | 1.0 | +| StateMismatch | Неверный или некорректный JSON | 1.0 | +| CTRLChar | Ошибка управляющего символа, возможно, неверная кодировка | 1.0 | +| Syntax | Синтаксическая ошибка | 1.0 | +| UTF8 | Некорректные для кодировки UTF-8 символы, возможно, неверная кодировка | 1.0 | +| Recursion | Одна или несколько зацикленных ссылок в кодируемом значении | 1.0 | +| InfOrNan | Одно или несколько значений NAN или INF в кодируемом значении | 1.0 | +| UnsupportedType | Передали значение с неподдерживаемым типом | 1.0 | +| InvalidPropertyName | Имя свойства не может быть закодировано | 1.0 | +| UTF16 | Некорректный для кодировки UTF-16 символ, возможно, некорректно закодирован | 1.0 | +| KeyIsNotArray | Ключ не содержит вложений, хотя от него требуется обратное | 1.0 | +| NotISerializable | Класс не реализует интерфейс ISerializable | 1.0 | + +### Методы и функции перечисления JsonErrorCode + +Перечисление содержит **статический метод** `static function FromLastError (): JsonErrorCode`, который получает код +ошибки из последней JSON ошибки. + +Например, при успешной загрузке, можем проверить ошибки: + + $errors = JsonErrorCode::FromLastError (); + +После того, как мы выведем `$errors`, мы получим `JsonErrorCode::None`. + +## Исключение JsonException + +Исключение расширяет класс `Exception`, поэтому может выбрасываться через `throw`. + +### Свойства + +Исключение содержит следующие свойства: + +- `?string $JsonString` - строка JSON (или null); +- `JsonErrorCode $ErrorCode` - код ошибки JSON; +- `?string $ErrorMessage` - сообщение об ошибке JSON (в отличие от функции json_last_error_msg(), данная переменная при + отсутствии ошибок выводит null, а не "No error"). + +### Методы и функции + +#### Конструктор. + +Конструктор принимает **3 необязательных параметра**: + +* `?string $json` - строка JSON (по умолчанию, `null`); +* `JsonErrorCode $errorCode` - код ошибки (по умолчанию, `JsonErrorCode::Unknown`); +* `?string $errorMessage` - сообщение об ошибке (по умолчанию, `null`). + +В результате создаётся новое исключение `JsonException`. + +Пример: + + throw new JsonException("{}", JsonErrorCode::Depth, "Пример"); + +Создаст исключение `JsonException`. + +## Методы и функции + +### Конструктор и деструктор. + +Конструктор не принимает никаких параметров. + +В результате создаётся новый класс `JsonReWriter`. + +**Пример:** + + // Контсуктор + $json = new JsonReWriter (); + // Деструктор + unset($json); + +Создаст и уничтожит класс `JsonReWriter`. + +### Сохранение и загрузка из файла. + +За сохранение и загрузку отвечают 2 метода: `SaveToFile` и `LoadFromFile`. + +#### Сохранение в файл (метод `SaveToFile`) + +Этот метод сохраняет содержимое JSON в файл. Он содержит **1 обязательный параметр**: + +* `string $fileName` - имя файла на диске. + +Метод возвращает `bool` - сохранены ли данные в файл: `true` - да, `false` - нет. + +Синтаксис: + + public function SaveToFile (string $fileName): bool + +**Пример:** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Сохраняем созданный JSON файл + $json->SaveToFile($fileName); + +Содержимое файла `test.json` представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +#### Загрузка файла (метод `LoadFromFile`) + +Этот метод загружает содержимое файла в класс. Он содержит **1 обязательный параметр**: + +* `string $fileName` - имя файла на диске. + +Метод возвращает `bool` - загружены ли данные из файла: `true` - да, `false` - нет. + +Синтаксис: + + public function LoadFromFile (string $fileName): bool + +**Пример:** +Пусть дан файл `test.json`, содержимое которого представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +Следующий код загрузит это содержимое в класс: + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Загружаю данные + $json->LoadFromFile($fileName); + +### Чтение данных + +Для чтения данных используется один общий метод `Read` и 7 его производных метода: `ReadString`, `ReadInt`, `ReadFloat`, +`ReadBool`, `ReadArray`, `ReadObject` и `ReadSerializable`. + +#### Метод `Read` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `mixed $default` (значение по умолчанию, задан по умолчанию в `null`). + +Этот метод возвращает `mixed`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function Read (string $key, mixed $default = null): mixed + +**Пример,** + + // Создаю класс + $json = new JsonReWriter(); + // Заполняю данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->Write("test3/test/res", json_encode([1, 2, 3])); + } catch (JsonException $e) { + echo $e->getMessage(); + } + + // Получаю значение + $float = (float)$json->Read("test/subtest/BBB")); + +В результате, переменная `$float` будет иметь значение `1.23`. + +#### Метод `ReadString` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `string $default` (значение по умолчанию, задан по умолчанию в `""`). + +Этот метод возвращает `string`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadString (string $key, string $default = ""): string + +#### Метод `ReadInt` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `int $default` (значение по умолчанию, задан по умолчанию в `0`). + +Этот метод возвращает `int`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadInt (string $key, int $default = 0): int + +#### Метод `ReadFloat` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `float $default` (значение по умолчанию, задан по умолчанию в `0.0`). + +Этот метод возвращает `float`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadFloat (string $key, float $default = 0.0): float + +#### Метод `ReadBool` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `bool $default` (значение по умолчанию, задан по умолчанию в `false`). + +Этот метод возвращает `bool`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadBool (string $key, bool $default = false): bool + +#### Метод `ReadArray` + +Это метод, который читает значение ключа JSON. Он имеет **1 обязательный параметр** `string $key` (ключ) и **1 +необязательный параметр** `array $default` (значение по умолчанию, задан по умолчанию в `[]`). + +Этот метод возвращает `array`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadArray (string $key, array $default = []): array + +#### Метод `ReadObject` + +Это метод, который читает значение ключа JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `object $default` (значение по умолчанию). + +Этот метод возвращает `object`: значение ключа JSON или значение по умолчанию. + +Синтаксис: + + public function ReadObject (string $key, object $default): object + +#### Метод `ReadSerializable` + +Это метод, который читает значение ключа JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `string $serializableClassName` (имя класса, реализующего интерфейс ISerializable, с namespace). + +Этот метод возвращает класс, реализующий интерфейс `ISerializable`. + +**Важно!** Этот метод может выбросить исключение `JsonException`, если класс, заданный в `$serializableClassName` не +реализует интерфейс `ISerializable`. + +Синтаксис: + + public function ReadSerializable (string $key, string $serializableClassName): ISerializable + +**Пример,** + +Пусть для примера, класс `Demo` из namespace `iam\namespace` реализует интерфейс `ISerializable`. + + // Создаю класс + $json = new JsonReWriter(); + // ... Здесь где-то загрузка данных + // Получаю класс + try { + /** + * @var Demo $unSerializableClass + */ + $unSerializableClass = $json->ReadSerializable("test", "iam\\namespace\\Demo"); + } catch (JsonException $e) { + echo $e->getMessage(); + } + +В результате, переменная `$unSerializableClass` будет содержать данные класса `Demo`. + +### Запись данных + +Для чтения данных используется один общий метод `Write` и 3 его производных метода: `WriteArray`, `WriteObject` и +`WriteSerializable`. + +**Важно!** Лобой из вышеуказанных методов может выбросить исключение `JsonException`, если ключ не содержит вложений, +хотя от него требуется обратное. + +#### Метод `Write` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `mixed $value` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function Write (string $key, mixed $value): void + +**Пример,** + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Сохраняем созданный JSON файл + $json->SaveToFile($fileName); + +Содержимое файла `test.json` представлено далее: + + { + "test": { + "subtest": { + "AAA": "123", + "BBB": 1.23 + } + }, + "test1": { + "test": 123 + }, + "test2": { + "test": true + }, + "test3": { + "test": { + "res": "[1,2,3]" + } + } + } + +#### Метод `WriteArray` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `array $array` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteArray (string $key, array $array): void + +#### Метод `WriteObject` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `object $value` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteObject (string $key, object $value): void + +#### Метод `WriteSerializable` + +Это метод, который записывает значение в ключ JSON. Он имеет **2 обязательных параметра**: + +- `string $key` (ключ); +- `ISerializable $serializableValue` (записываемое значение). + +Этот метод ничего не возвращает. + +Синтаксис: + + public function WriteSerializable (string $key, ISerializable $serializableValue): void + +**Пример,** +Пусть для примера, класс `Demo` из namespace `iam\namespace` реализует интерфейс `ISerializable`. + + // Имя файла + $fileName = __DIR__ . "/test.json"; + // Создаём класс + $json = new JsonReWriter(); + // Создаём класс Demo + $serializableClass = new Demo(...); + // Заполним данными + try { + $json->WriteSerializable("test", $serializableClass); + } catch (JsonException $e) { + echo $e->getMessage(); + } + ... + +### Работа с ключами JSON + +Для работы с ключами JSON есть 2 метода: `IsKeyExists` и `GetKeys`. + +#### Метод `IsKeyExists` + +Это метод проверяем наличие ключа в JSON. Он имеет **1 обязательный параметр** - `string $key` (ключ). + +Этот метод возвращает `bool`: `true` если ключ найден и `false` в противном случае. + +Синтаксис: + + public function IsKeyExists (string $key): bool + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Проверяем ключи + $check1 = $json->IsKeyExists("test/subtest/AAA"); + $check2 = $json->IsKeyExists("test/subtest/ССС"); + +В результате, `$check1` будет `true`, а `$check2` - `false`. + +#### Метод `GetKeys` + +Это метод получает список ключей. Он имеет **2 необязательных параметра**: + +- `string $parentKey` (ключ родителя (или "" (установлено по умолчанию) для всех); +- `bool $includeChildren` (нужно ли включать дочерние ключи (по умолчанию, да)). + +Этот метод возвращает `array`: список ключей. + +Синтаксис: + + public function GetKeys (string $parentKey = "", bool $includeChildren = true): array + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Получаем ключи + $keys1 = $json->GetKeys("test"); + $keys2 = $json->GetKeys("test", false); + $keys3 = $json->GetKeys(); + +В результате, `$key1` будет следующим массивом: + + [ + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB" + ] + +`$key2` будет следующим массивом: + + [ + "subtest" + ] + +`$key3` будет следующим массивом: + + [ + "test", + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB", + "test1", + "test1/test", + "test2", + "test2/test", + "test3", + "test3/test", + "test3/test/res" + ] + +### Удаление ключей JSON + +Для удаления ключей JSON есть 2 метода: `DeleteKey`, который удаляет только определённый ключ и `Clear`, который удаляет +**все ключи** из json-файла. + +#### Метод `DeleteKey` + +Это метод удаляет только определённый ключ в JSON. Он имеет **1 обязательный параметр** - `string $key` (ключ). + +Этот метод возвращает `bool` - результат удаления ключа: `true` - удаление прошло успешно, `false` - произошла ошибка +при удалении. + +Синтаксис: + + public function DeleteKey (string $key): bool + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Получаемем ключи до удаления + $check1 = $json->GetKeys("test/subtest"); + // Удаляем ключ + $this->DeleteKey("test/subtest/BBB"); + // Получаемем ключи после удаления + $check2 = $json->GetKeys("test/subtest"); + +В результате, `$check1` будет + + [ + "test/subtest", + "test/subtest/AAA", + "test/subtest/BBB" + ] + +а `$check2`: + + [ + "test/subtest", + "test/subtest/AAA" + ] + +#### Метод `Clear` + +Это метод удаляет **все ключи** из json-файла. Он не имеет никаких параметров и ничего не возвращает. + +Синтаксис: + + public function Clear (): void + +**Пример,** + + // Создаём класс + $json = new JsonReWriter(); + // Заполним данными + try { + $json->Write("test/subtest/AAA", "123"); + $json->Write("test/subtest/BBB", 1.23); + $json->Write("test1/test", 123); + $json->Write("test2/test", true); + $json->WriteArray("test3/test/res", [1, 2, 3]); + } catch (JsonException $e) { + echo $e->getMessage(); + } + // Очищаем + $json->Clear(); + // Получаем ключи + $keys = $json->GetKeys(); + +В результате, `$key` будет следующим массивом: + + [ + ] \ No newline at end of file diff --git a/tests/classes/JsonReWriterTest.php b/tests/classes/JsonReWriterTest.php index e067d99..f333205 100644 --- a/tests/classes/JsonReWriterTest.php +++ b/tests/classes/JsonReWriterTest.php @@ -3,7 +3,7 @@ namespace goodboyalex\php_components_pack\tests\classes; use goodboyalex\php_components_pack\classes\File; -use goodboyalex\php_components_pack\classes\JsonReWriter; +use goodboyalex\php_components_pack\classes\BoolEx; use goodboyalex\php_components_pack\exceptions\JsonException; use goodboyalex\php_components_pack\tests\data\A; use goodboyalex\php_components_pack\tests\data\C; @@ -15,7 +15,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); } @@ -43,7 +43,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/test", 123); } @@ -58,7 +58,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/test1", false); $json->Write("test/test2", true); @@ -75,7 +75,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/test", "test string"); } @@ -95,7 +95,7 @@ class JsonReWriterTest extends TestCase if (file_exists($fileName)) unlink($fileName); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); @@ -123,7 +123,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); @@ -143,7 +143,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); @@ -165,7 +165,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); $class = new A("test", 123, true); @@ -188,7 +188,7 @@ class JsonReWriterTest extends TestCase if (file_exists($fileName)) unlink($fileName); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); @@ -205,7 +205,7 @@ class JsonReWriterTest extends TestCase unset($json); - $json = new JsonReWriter(); + $json = new BoolEx(); $json->LoadFromFile($fileName); @@ -218,7 +218,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); @@ -240,7 +240,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); $json->Write("test/subtest/BBB", 1.23); @@ -261,7 +261,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test/subtest/AAA", "123"); $json->Write("test/subtest/BBB", 1.23); @@ -283,7 +283,7 @@ class JsonReWriterTest extends TestCase $serializableClass = new C("test", 123, true); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->WriteSerializable("test", $serializableClass); @@ -306,7 +306,7 @@ class JsonReWriterTest extends TestCase { $this->PrepareForTest(); - $json = new JsonReWriter(); + $json = new BoolEx(); try { $json->Write("test", 1.23); }