proudmore
@proudmore

Как сделать конструктор класса правильно?

Здравствуйте. У меня есть класс, который хранит информацию о человеке. И есть конструктор, который принимает на вход id человека, берет информацию из базы и наполняет объект. Нужно добавить возможность создавать объект пользователя, информации о котором в базе нет.
Как это сделать?
public function __construct($id){
		$mysqli = db_connect();
		$req = "SELECT u.ID, u.name, u.age, u.city_id, c.city_name FROM users AS u INNER JOIN cities AS c ON (c.city_id = u.city_id) WHERE u.ID = $id";
		$res = $mysqli->query($req);
		if($res !== false){
			if($res->num_rows == 1 ){
				while($row = $res ->fetch_assoc()){
					$this-> id = $row['ID'];
					$this-> username =  $row['name'];
					$this-> city_name = $row['city_name'];
					$this-> city_id = $row['city_id'];
					$this-> age = $row['age'];
				}
			}  else return false;
		} else return false;
	}
  • Вопрос задан
  • 383 просмотра
Решения вопроса 1
AlekseyNemiro
@AlekseyNemiro
full-stack developer
Обычно это делается в отдельном методе, наподобие Save.

У пользователя, которого нет в базе, $this->id будет нулевым.

И для загрузки данных лучше сделать отдельный метод - Load.

public function __construct($id = NULL)
{
  $this->id = $id;
  $this->Load();
}

public function Load()
{
  // идентификатор не указан, загружать данные не нужно
  if (!isset($this->id) || (int)$this->id == 0)
  {
    return false;
  }

  // указан идентификатор, загружаем данные в текущий экземпляр класса
  $mysqli = db_connect();

  $req = 'SELECT u.ID, u.name, u.age, u.city_id, c.city_name FROM users AS u '.
         'INNER JOIN cities AS c ON (c.city_id = u.city_id) '.
         'WHERE u.ID = '.$this->id; // опасно так передавать в запрос данные

  $res = $mysqli->query($req);

  if ($res !== false){
    if ($res->num_rows == 1 )
    {
      // смысла в цикле нет, ожидается ведь одна строка данных
      while ($row = $res->fetch_assoc())
      {
        $this->id = $row['ID'];
        $this->username =  $row['name'];
        $this->city_name = $row['city_name'];
        $this->city_id = $row['city_id'];
        $this->age = $row['age'];
      }
    }
    else
    {
      return false;
    }
  }
  else
  {
    return false;
  }
}

public function Save()
{
  $sql = '';
  $params = [];

  if (!isset($this->id) || (int)$this->id == 0)
  {
    // запрос на добавление данных в базу
    $sql = 'INSERT INTO users (name, city_id, age) VALUES (?, ?, ?)';
    // параметры запроса
    $params = [$this->username, $this->city_id, $this->age];
  }
  else
  {
    // запрос на обновление данных в базе
    $sql = 'UPDATE users SET name = ?, city_id = ?, age = ? WHERE ID = ?';
    // параметры запроса
    $params = [$this->username, $this->city_id, $this->age, $this->id];
  }

  // код выполнения запроса
  // не могу быть уверен в коде, давно не писал и проверять лень
  // должно быть что-то типа такого:

  $mysqli = db_connect(); // лучше сделать отдельный метод для создания и закрытия соединений

  // подготавливаем запрос
  $s = $mysqli->prepare($sql);

  // выполняем запрос с указанными параметрами
  $s->execute($params);

  // тут еще неплохо бы закрыть все соединения :-)
}

Можно пойти дальше и сделать базовый класс, который будет содержать готовые методы Load и Save.
Либо сделать отдельный класс, который будет получать данные и заполнять экземпляры классов этими данными, сохранять и удалять данные. В таком случае классы таблиц (сущности) будут просто описывать структуру данных в базе и не будут выполнять никаких действий. Этот вариант мне нравится больше, т.к. он чище (проще) и более гибкий.

Придется придумать, как сопоставлять данные, если имена свойств не соответствую именам полей в базе. Скорее всего интерфейсы нужно будет использовать. Также учесть свойства, которые не определены в базе (которые следует игнорировать).

Для работы со структурой классов потребуется использовать Reflection.
В общих чертах примерно следующим образом:

// создаем экземпляр класса User
$instance = new User();

// получаем информацию об экземпляре класса
$r = new \ReflectionClass($instance);

// получаем список публичных свойств
$propeties = $r->getProperties(\ReflectionProperty::IS_PUBLIC);

// перебираем все свойства
foreach ($propeties as $property)
{
  // получаем имя свойства
  $propertyName = $property->getName();
  // получаем значение свойства
  $propertyValue = $property->getValue();
  // и далее можно использовать полученную информацию
  // для формирования динамических запросов к базе

  // полученные из базы данные можно передать в нужные свойства
  $property->setValue("значение из базы");
}

Готовое решение найти будет проще :-)
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Sanasol
@Sanasol Куратор тега PHP
нельзя просто так взять и загуглить ошибку
}  else return false;
    } else return false;

конструкторы ничего не возвращают.

Просто создавайте пустой инстанс объекта, заполняйте данные, потом сохраняйте его в базу.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы