TGViewer
Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter @phpproglib · 10.5K subscribers
Post #6412 1.81K

Forwarded from Библиотека собеса по PHP | вопросы с собеседований

✔️ PHP-тест: Exception handling + PDO транзакции + молчаливая потеря данных

Код выглядит аккуратно. Но данные теряются, и никто не знает почему 👇

📦 Задание

Есть сервис для обработки платежей. Код покрыт тестами, транзакции есть, ошибки логируются. На проде раз в несколько дней часть платежей пропадает — в БД нет записи, в логах нет ошибок, пользователь уверен что оплатил.

// src/Payment/PaymentService.php
class PaymentService
{
public function __construct(
private PDO $pdo,
private Logger $logger,
private Notifier $notifier,
) {}

public function process(PaymentDTO $dto): bool
{
try {
$this->pdo->beginTransaction();

$paymentId = $this->insertPayment($dto);
$this->updateBalance($dto->userId, $dto->amount);
$this->insertAuditLog($paymentId, $dto);

$this->pdo->commit();

$this->notifier->sendReceipt($dto->userId, $paymentId);

return true;

} catch (NotificationException $e) {
$this->logger->warning('Receipt failed', ['error' => $e->getMessage()]);
return true;

} catch (Throwable $e) {
$this->logger->error('Payment failed', ['error' => $e->getMessage()]);
$this->pdo->rollBack();
return false;
}
}

private function insertPayment(PaymentDTO $dto): int
{
$stmt = $this->pdo->prepare(
'INSERT INTO payments (user_id, amount, status) VALUES (?, ?, ?)'
);
$stmt->execute([$dto->userId, $dto->amount, 'pending']);
return (int) $this->pdo->lastInsertId();
}

private function updateBalance(int $userId, float $amount): void
{
$stmt = $this->pdo->prepare(
'UPDATE balances SET amount = amount - ? WHERE user_id = ?'
);
$stmt->execute([$amount, $userId]);

if ($stmt->rowCount() === 0) {
throw new \RuntimeException("Balance record not found for user $userId");
}
}

private function insertAuditLog(int $paymentId, PaymentDTO $dto): void
{
// Пишем в отдельную audit БД через отдельное соединение
$this->auditPdo->prepare(
'INSERT INTO audit_log (payment_id, user_id, amount) VALUES (?, ?, ?)'
);
// ... execute
}
}


🔹 Задачи

— Найти сценарий, при котором платёж коммитится в БД, но return true не доходит до контроллера — и данные считаются потерянными
— Объяснить проблему
— Предложить исправленную структуру

Ставьте → 🔥 если нравится формат. Если нет → 🌚

💬 Решения пишите в комменты под спойлер — сравним подходы.
  • 🔥 12
  • 👍 4
  • 🌚 3
  • ❤ 2
More from @phpproglib
  1. Sep 21, 2026⚡️ PHP 8.6 выйдет 19 ноября 2026 года. Сейчас версия находится в beta. Самые заметные изме…
  2. Sep 20, 2026❓ Какие существуют проблемы в многопоточной среде? Основные проблемы многопоточности: 1️⃣…
  3. Sep 19, 2026🌞 В Symfony 8.2 появилось 29 новых Bundle — теперь компоненты вроде Mailer, Messenger и C…
  4. Sep 19, 2026А вы уже забрали свой подарок ко Дню программиста? К вашему профессиональному празднику Tp…
  5. Sep 18, 2026🐸 Библиотека пхпшника
  6. Sep 17, 2026🛠 `str_contains` и семья: проверяем строки без ловушек Проверка через strpos годами путал…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →