#php #oop #pdo
#php #ооп #pdo
Вопрос:
Я пытаюсь создать объект «User» внутри моего класса «User» на основе свойств, которые я сохранил в своей базе данных, для подключения к которой я использую PDO.
Я поискал несколько страниц в Google и обнаружил, что большинство людей используют для этого метод fetchObject. Прямо сейчас я пытаюсь использовать это для создания объекта этого текущего класса, но я продолжаю получать ошибку:
Неустранимая ошибка: неперехваченный ArgumentCountError: Слишком мало аргументов для функции User::__construct(), передано 0 и ожидается ровно 11 …
Все продолжают использовать это в Интернете, но, похоже, я не могу найти их конструкторы, потому что у них может не быть никаких атрибутов для получения.
Мой текущий код таков:
public static function createUserBySQL($id)
{
$stmt = BD::getConnection()->prepare("SELECT * FROM user WHERE username = ?");
$stmt->execute([$id]);
$user = $stmt->fetchObject(__CLASS__);
var_dump($user);
return $user;
}
Это может быть легко решить, но я впервые выполняю ООП на PHP с помощью PDO, поэтому я еще не знаю всех советов и хитростей, которые можно так легко обойти 😉
Спасибо,
mikeysantana
БЫСТРОЕ РЕДАКТИРОВАНИЕ: Все атрибуты из экземпляра «User» являются частными, и я хотел сохранить это таким образом, чтобы поддерживать логику кода.
Комментарии:
1.
fetchObject()
не работает при передаче значений столбцов конструктору. Он создает объект, инициализирует все свойства из столбцов, а затем вызывает конструктор без аргументов.2. Это почти единственное, что описано в руководстве под этой записью: php.net/manual/en/pdostatement . fetchobject.php
3. fetchObject делает какие-то волшебные вещи. Он непосредственно устанавливает атрибуты объекта. Конструктор не должен ожидать никаких параметров.
Ответ №1:
Вам нужно сделать параметры вашего конструктора необязательными. В документации говорится:
Когда объект извлекается, его свойства присваиваются из соответствующих значений столбца, а затем вызывается его конструктор.
При вызове конструктора аргументы не предоставляются, вот почему вы получаете эту ошибку.
Конструктору необходимо проверить, были ли аргументы предоставлены явно, и заполнять свойства только тогда, когда они есть. Есть несколько примеров того, как это сделать, в разделе комментариев приведенной выше документации.
Ответ №2:
После нескольких попыток мне действительно удалось заставить это работать без установки значений по умолчанию в конструкторах или какого-либо обходного пути. Ключ находится в PDO::FETCH_PROPS_LATE
* и массиве аргументов в конце.
Решение
$ctor_args = array(1, 'a placeholder')// pass an array of placeholder values.
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", $ctor_args);
Рабочий пример
class Post
{
private $id;
private $content;
function __construct($id, $content){
$this->id = $id;
$this->content = $content;
}
public function getId(){
return $this->id;
}
}
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", [0,0]);
print_r($result[0]->getId());
// 1
print_r($result);
// Array
// (
// [0] => Post Object
// (
// [id:Post:private] => 1
// [content:Post:private] => value from the db
// )
// [1] => Post Object
// (
// [id:Post:private] => 2
// [content:Post:private] => it is working!
// )
// )
Предупреждение:
*При PDO::FETCH_PROPS_LATE
использовании с PDO::FETCH_CLASS
конструктор класса вызывается перед присвоением свойств из соответствующих значений столбца.
Поэтому имейте в виду, что конструктор будет вызываться со значениями-заполнителями, а не с данными из базы данных, поэтому это решение (абсолютно) не рекомендуется, если вы манипулируете входными значениями сразу внутри конструктора. Но отлично работает для простой инициализации свойств класса.
Проблема с этим
class Count{
private $number5;
function __construct($number)
{
$this->number5 = $number;
print_r(10 / $this->number5); // should be 10/5, so print 2
}
}
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Count", [0]);
// Warning: Division by zero in C:xampphtdocsappModelPost.php on line 15 INF
// Warning: Division by zero in C:xampphtdocsappModelPost.php on line 15 INF
Да, он вызывает конструктор дважды.
Комментарии:
1. Чувак, если это то, о чем я думаю, то это прорыв. Надеюсь, вы не ошибаетесь. Собираемся проверить
2. а, понятно. вы только что указали поддельные параметры конструктора. умный, но не совсем то, что я думал.
3. Что ж, это работает, и это проще, чем использовать функции в качестве оболочек или добавлять логические проверки нулей.
4. итак, вы просто могли бы сделать это встроенным массивом,
"Post", [0,0]);
не знаю, зачем беспокоиться о отдельной переменной5. Я вижу, если у вас есть какая-то логика внутри конструктора, он будет выполняться с поддельными значениями.
Ответ №3:
Спасибо всем за вашу помощь.
Чтобы помочь будущим читателям этого вопроса, вот мое решение:
Я сохранил метод «createUserBySQL», описанный выше, таким, какой он есть, я только изменил свой конструктор.
Конструктор теперь имеет все свои атрибуты в подписи необязательно, вот так:
function __construct($name = null, $surname = null ...)
Внутри конструктора я выполнил проверку, чтобы увидеть, все ли аргументы были нулевыми. Поскольку у меня их было 11, выполнение инструкции if для всех было бы довольно раздражающим, поэтому я использовал метод func_get_args(), который возвращает массив со всеми аргументами, переданными конструктору.
Окончательный конструктор будет выглядеть примерно так:
function __construct($firstname = null, $surname = null, ...)
{
if (func_get_args() != null){
$this->firstname = $firstname;
$this->surname = $surname;
...
}
}