diff --git a/sources/classes/FileHash.php b/sources/classes/FileHash.php
new file mode 100644
index 0000000..51aa549
--- /dev/null
+++ b/sources/classes/FileHash.php
@@ -0,0 +1,79 @@
+HashBy = $HashBy;
+ $this->Hash = match ($HashBy) {
+ HashGetType::ByString => $this->pGetHash($str),
+ HashGetType::ByFile => $this->pGetFileHash($str)
+ };
+ }
+
+ /**
+ * Получение хэша файла по строке.
+ *
+ * @param string $str Строка.
+ *
+ * @return string Хэш строки.
+ */
+ private function pGetHash (string $str): string
+ {
+ return hash('sha256', $str);
+ }
+
+ /**
+ * Получение хэша файла по имени файла.
+ *
+ * @param string $fileName Имя файла.
+ *
+ * @return string Хэш файла.
+ */
+ private function pGetFileHash (string $fileName): string
+ {
+ return hash_file('sha256', $fileName);
+ }
+
+ /**
+ * Сравнивает текущий хэш с хэшем otherHash
и выдаёт true
, если совпадают, и
+ * false
, если не совпадают.
+ *
+ * @param FileHash $otherHash Другой хэш.
+ *
+ * @return bool true
, если совпадают, и false
, если не совпадают.
+ */
+ public function IsEqual (FileHash $otherHash): bool
+ {
+ return StringExtension::Compare($this->Hash, $otherHash->Hash, true) === 0;
+ }
+}
\ No newline at end of file
diff --git a/sources/classes/TwoDimSize.php b/sources/classes/TwoDimSize.php
new file mode 100644
index 0000000..a52f2de
--- /dev/null
+++ b/sources/classes/TwoDimSize.php
@@ -0,0 +1,183 @@
+pWidth;
+ }
+ set {
+ $this->pWidth = $this->NoNegativeValues ? max($value, 0) : $value;
+ }
+
+ }
+
+ /**
+ * @var int $Height Ширина (публичная)
+ */
+ public int $Height {
+ get {
+ return $this->pHeight;
+ }
+ set {
+ $this->pHeight = $this->NoNegativeValues ? max($value, 0) : $value;
+ }
+
+ }
+
+ /**
+ * @var int $pWidth Длина (приватное)
+ */
+ private int $pWidth = 0;
+
+ /**
+ * @var int $pHeight Ширина (приватное)
+ */
+ private int $pHeight = 0;
+
+ /**
+ * Конструктор.
+ *
+ * @param int $width Длина.
+ * @param int $height Ширина.
+ * @param bool $noNegativeValues Значения не должны быть отрицательными.
+ */
+ public function __construct (int $width = 0, int $height = 0, bool $noNegativeValues = true)
+ {
+ $this->Width = $width;
+ $this->Height = $height;
+ $this->NoNegativeValues = $noNegativeValues;
+ }
+
+ /**
+ * Конвертация в строку (магический метод).
+ *
+ * @return string Строка.
+ */
+ public function __toString (): string
+ {
+ return $this->AsString();
+ }
+
+ /**
+ * Конвертация в строку (расширенный метод).
+ *
+ * @param string $delimiter Делитель размера.
+ *
+ * @return string Строка.
+ */
+ public function AsString (string $delimiter = self::DEFAULT_DELIMITER): string
+ {
+ return $this->Width . $delimiter . $this->Height;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function Serialize (): string
+ {
+ // Получаю строковое значение
+ $str = $this->AsString("x");
+
+ // Добавляю допустимы ли отрицательные значения
+ $str .= $this->NoNegativeValues ? "x1" : "x0";
+
+ // Возвращаю строку
+ return $str;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function UnSerialize (string $serialized): void
+ {
+ // Десериализую строку
+ $result = explode("x", $serialized);
+
+ // Присваиваю параметры
+ $this->NoNegativeValues = $result[2] === "1";
+
+ // Объединяю длину и ширину
+ $tdSize = $result[0] . self::DEFAULT_DELIMITER . $result[1];
+
+ // Пытаюсь получить размер
+ try {
+ $result = self::Parse($tdSize, noNegativeValues: $this->NoNegativeValues);
+ }
+ catch (Exception $e) {
+ $result = new TwoDimSize(noNegativeValues: $this->NoNegativeValues);
+ }
+
+ // Присваиваю длину
+ $this->Width = $result->Width;
+
+ // Присваиваю ширину
+ $this->Height = $result->Height;
+ }
+
+ /**
+ * Получение размера из строки.
+ *
+ * @param string $str Строка.
+ * @param string $delimiter Разделитель размеров.
+ * @param bool $noNegativeValues Значения не должны быть отрицательными.
+ *
+ * @return TwoDimSize Модель размеров.
+ * @throws Exception Если в строке str
не содержится символа delimiter
или таких
+ * разделителей слишком много.
+ */
+ public static function Parse (string $str, string $delimiter = self::DEFAULT_DELIMITER,
+ bool $noNegativeValues = true): TwoDimSize
+ {
+ // Разделяю значения
+ $splitSizes = explode($delimiter, $str);
+
+ // Проверяю, что массив имеет ровно два элемента
+ if (count($splitSizes) != 2)
+ throw new Exception(sprintf("Похоже, что в строке %s не содержится символа «%s» или таких разделителей слишком много!",
+ $str, $delimiter));
+
+ // Пытаюсь получить длину
+ $width = filter_var($splitSizes[0], FILTER_VALIDATE_INT);
+
+ // Если не удалось получить длину
+ if ($width === false)
+ $width = 0;
+
+ // Пытаюсь получить ширину
+ $height = filter_var($splitSizes[1], FILTER_VALIDATE_INT);
+
+ // Если не удалось получить ширину
+ if ($height === false)
+ $height = 0;
+
+ // Вывожу значение
+ return new TwoDimSize($width, $height, $noNegativeValues);
+ }
+}
\ No newline at end of file
diff --git a/sources/enums/HashGetType.php b/sources/enums/HashGetType.php
new file mode 100644
index 0000000..8d1fbaa
--- /dev/null
+++ b/sources/enums/HashGetType.php
@@ -0,0 +1,29 @@
+PrepareForTest();
+
+ $fileHash = new FileHash("Тестовое слово");
+ $this->assertEquals("000e22f7ba01ae35f781bc3069038110c46593306cafef6b489f7c83b34629b7", $fileHash->Hash);
+
+ $fileHash = new FileHash(__DIR__ . '/../data/A.php', HashGetType::ByFile);
+ $this->assertEquals("fc8dad93af5de5dd7c7d64e04faadfa22557e577a1538737fe462a5f78699fa2", $fileHash->Hash);
+
+ $fileHash = new FileHash(__DIR__ . '/../data/B.php', HashGetType::ByFile);
+ $this->assertEquals("f419262e46e9461517af46d0c1e4faf25f38990bb50351b691d84f1ad51f2299", $fileHash->Hash);
+ }
+
+ private function PrepareForTest (): void
+ {
+ require_once __DIR__ . '/../../sources/traits/EnumExtensionsTrait.php';
+ require_once __DIR__ . '/../../sources/enums/HashGetType.php';
+ require_once __DIR__ . '/../../sources/extensions/StringExtension.php';
+ require_once __DIR__ . '/../../sources/classes/FileHash.php';
+ }
+
+ public function testIsEqual ()
+ {
+ $this->PrepareForTest();
+
+ $fileHash = new FileHash("Тестовое слово");
+
+ $this->assertTrue($fileHash->IsEqual(new FileHash("Тестовое слово")));
+ $this->assertFalse($fileHash->IsEqual(new FileHash("Тестовое слово2")));
+ }
+}
\ No newline at end of file
diff --git a/tests/classes/TwoDimSizeTest.php b/tests/classes/TwoDimSizeTest.php
new file mode 100644
index 0000000..df7acf0
--- /dev/null
+++ b/tests/classes/TwoDimSizeTest.php
@@ -0,0 +1,66 @@
+PrepareForTest();
+
+ try {
+ $size = TwoDimSize::Parse("10x20", "x");
+ }
+ catch (Exception $e) {
+ $this->fail($e->getMessage());
+ }
+
+ $this->assertEquals(10, $size->Width);
+ $this->assertEquals(20, $size->Height);
+
+ }
+
+ private function PrepareForTest (): void
+ {
+ require_once __DIR__ . '/../../sources/interfaces/ISerializable.php';
+ require_once __DIR__ . '/../../sources/classes/TwoDimSize.php';
+ }
+
+ public function test__toString ()
+ {
+ $this->PrepareForTest();
+
+ $size = new TwoDimSize(10, 20);
+
+ $this->assertEquals("10:20", $size->__toString());
+ }
+
+ public function testSerialize ()
+ {
+ $this->PrepareForTest();
+
+ $size = new TwoDimSize(10, 20);
+
+ $this->assertEquals("10x20x1", $size->Serialize());
+
+ }
+
+ public function testUnSerialize ()
+ {
+ $this->PrepareForTest();
+
+ $serialized = "10x20x1";
+
+ $size = new TwoDimSize();
+
+ $size->UnSerialize($serialized);
+
+ $this->assertEquals(10, $size->Width);
+ $this->assertEquals(20, $size->Height);
+ $this->assertTrue($size->NoNegativeValues);
+ }
+}
\ No newline at end of file