Если в двух словах, ваш класс - днище. Вы попытались объединить вместе принципиально разные вещи, что не правильно. SOLID - это важно.
Что касается оформления - PSR-1, PSR-2, PSR-4 - учим и используем.
Юзайте скалярный тайпхинтинг, с ним реально проще жить.
Собсно какие сущности у вас объеденены:
1. Система инициализации подключения к БД. У вас это просто хардкод, даже хардкор. Во вне этого класса создаем PDO и передаем аргументом конструктора.
2. Хранилище иерархических данных (ваши get и set) их вполне можно оставить, только добавьте валидацию.
3. Исключения:
- \InvalidArgumentException - "ты впихнул какую-то хрень"
- \DomainException - "ошибка данных", например пользователя с таким логином нет.
- \LogicalException - "я хз как такое произошло", например удаляем не существующий файл
- \RuntimeException - "я хз, что с этим делать", например пытаемся записать в файл, который кто-то удалил
4. Сериализатор, его тоже не помешает вынести и JSON в бд хранить - плохая идея
5. Работу с БД стоит вынести в отдельный класс Repository
<?php
declare(strict_types=1); // !!!! Забыли
namespace MyVendor\MyProject\Path\To; // !!!! Забыли
/**
* Class treeData
* Singleton класс для работы с многомерными пользовательскими массивами
*/
// !!!! Начну с далека: Singleton - антипаттерн, пока что переваривайте эту информацию
class treeData
{
protected static $_instance, $data, $pdo, $id;
/**
* @param $id
* @return treeData
* @throws Exception
*/
public static function getInstance(/* !!!! используйте скалярный тайпхинтинг */$id) { // !!!! Не используйте статические методы
if (self::$_instance === null) {
self::$_instance = new self($id);
} else {
// !!!!
throw new Exception("Попытка повторного создания экземпляра Singleton класса");
}
return self::$_instance;
}
/**
* Соединение с БД
* @return PDO // !!!! может \PDO?
*/
private static function db(){ // !!!! Не используйте статические методы
// !!!! Этому методу тут не место. Connection к БД - это вполне отдельная сущность, а у вас это захардкоженное создание PDO
$host = '127.0.0.1';
$db = 'for_test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
$pdo = new PDO($dsn, $user, $pass);
}
catch (PDOException $e){
die($e->getMessage());
}
return $pdo;
}
/**
* @param $id // !!!! А тип где?
* @return mixed
*/
private static function getFromDb(/* !!!! используйте скалярный тайпхинтинг */$id){ // !!!! Я понять не могу, вот зачем вам этот метод?
// !!!! БД - отдельно, претрубации с деревом - отдельно, не мешайте все в кучу!
$sql = "SELECT `data` FROM tree2 WHERE id = ? LIMIT 1";
$stmt = self::$pdo->prepare($sql);
$stmt->execute(array($id));
$row = $stmt->fetch(PDO::FETCH_LAZY);
return $row;
}
/**
* Сохранение в БД.
*/
private static function saveToDb() {// !!!! Я понять не могу, вот зачем вам этот метод?
// !!!! БД - отдельно, претрубации с деревом - отдельно, не мешайте все в кучу!
$sql = "UPDATE tree2 SET `data` = :data WHERE id = :id";
$stmt = self::$pdo->prepare($sql);
$stmt->execute(array(':id' => self::$id, ':data' => self::mySerialize(self::$data)));
}
/**
* treeData constructor.
* @param $id // !!!! Указать требуемый тип религия не позволяет?))
* @throws Exception
*/
private function __construct(/* !!!! используйте скалярный тайпхинтинг */$id) {
if(!is_int($id)){
throw new Exception("ИД пользователя должно быть целым числом.");
}// !!!! А что если id = -256?
self::$pdo = self::db();
self::$id = $id;
$row = self::getFromDb($id);
$data = $row['data'];
//Подготовка данных
if(empty($data)){ //Массив пуст, создаем новый
self::$data = array();
} else{ //Работаем с данными
self::$data = self::myDeserialize($data);
}
}
/**
* Для предотвращения возможного клонирования объекта
*/
private function __clone() { //запрещаем клонирование объекта модификатором private
}
/**
* Статическая функция для сериализации масива
* @param $data
* @return string
*/
private static function mySerialize(/* !!!! используйте скалярный тайпхинтинг */$data){ // !!!! Зачем сериализация в классе по работе с БД?
return json_encode(serialize($data));
}
/**
* Статическая функция для десиарилизации массива
* @param $data
* @return mixed
*/
private static function myDeserialize(/* !!!! используйте скалярный тайпхинтинг */$data){ // !!!! Зачем десериализация в классе по работе с БД?
return unserialize(json_decode($data));
}
/**
* Обеспечивает возможность получения конкретной переменной из приватной переменной data
* @param String $path // !!!! В php нет типа String, есть string
* @return array
* @throws Exception
*/
public static function get(/* !!!! используйте скалярный тайпхинтинг */$path){ // !!!! get что?
// !!!! Что если path - исключение?
$pathArray = explode('/', $path); //Получаю массив с путем
$level = self::$data; //Начальный массив
foreach ($pathArray as $key){
if(array_key_exists($key, $level)){
$level = $level[$key];
} else {
throw new Exception("Индекса '$key' не существует");
}
}
return $level;
}
/**
* беспечивает возможность установки новой или замещения текущей переменной.
* @param $path // !!!! где типы данных?
* @param $value
*/
public static function set(/* !!!! используйте скалярный тайпхинтинг */$path, $value){ // !!!! set что?
// !!!! Что если path - исключение?
//Получаем путь
$pathArray = explode('/', $path);
//Вносим в массив данные
$level =& self::$data;
foreach ($pathArray as $key) {
if (!array_key_exists($key, $level) or !is_array($level[$key])) {
$level[$key] = [];
}
$level =& $level[$key];
}
if(is_array($level) && is_array($value)){
$level = array_merge($level, $value);
} else {
$level = $value;
}
//Запись в БД
self::saveToDb();
}
}