Clase și obiecte în PHP
Programarea Orientată pe Obiecte (OOP) permite organizarea codului în clase care definesc tipuri de obiecte și comportamentele lor. O clasă este un șablon, iar un obiect este o instanță a unei clase.
De ce să folosim clase și obiecte?
- Îmbunătățește structura și organizarea codului.
- Permite reutilizarea codului prin instanțierea de obiecte multiple.
- Facilitează mentenanța și extinderea aplicațiilor mari.
Definirea unei clase și crearea unui obiect
Exemplu simplu de clasă care descrie un utilizator:
<?php
// Definirea clasei
class User {
// Proprietăți
public $name;
public $email;
// Metodă pentru afișarea informațiilor
public function showInfo() {
echo "Nume: $this->name, Email: $this->email <br>";
}
}
// Crearea unui obiect
$user1 = new User();
$user1->name = "Ion Popescu";
$user1->email = "ion.popescu@example.com";
// Apelarea metodei
$user1->showInfo();
?>
Explicație pas cu pas
- Am creat o clasă
Usercu două proprietăți:$nameși$email. - Am definit o metodă
showInfo()care afișează proprietățile obiectului. - Am instanțiat un obiect
$user1folosind cuvântul cheienew. - Am setat valorile proprietăților obiectului.
- Am apelat metoda
showInfo()pentru a afișa informațiile.
Acesta este fundamentul OOP în PHP: clasele definesc structura și comportamentul, iar obiectele sunt instanțe ale acelor clase.
Proprietăți & metode în PHP
În OOP, proprietățile sunt variabilele dintr-o clasă care definesc starea unui obiect, iar metodele sunt funcțiile care definesc comportamentul obiectului.
Definirea proprietăților și metodelor
<?php
class User {
// Proprietăți
public $name;
public $email;
private $password; // proprietate privată
// Metodă publică
public function setPassword($pass) {
$this->password = password_hash($pass, PASSWORD_DEFAULT);
}
// Metodă publică pentru afișare
public function showInfo() {
echo "Nume: $this->name, Email: $this->email <br>";
}
// Metodă privată (nu poate fi apelată din afara clasei)
private function getPassword() {
return $this->password;
}
}
// Crearea obiectului
$user = new User();
$user->name = "Maria Ionescu";
$user->email = "maria.ionescu@example.com";
$user->setPassword("parola123");
// Apelăm metoda publică
$user->showInfo();
// Nu putem face:
echo $user->password; // eroare, proprietate privată
?>
Explicație pas cu pas
$nameși$emailsunt publice - pot fi accesate și modificate direct din afara clasei.$passwordeste privată - poate fi accesată doar din interiorul clasei.- Metoda
setPassword()criptează parola folosindpassword_hash()și setează proprietatea privată$password. - Metoda
showInfo()afișează informațiile publice ale obiectului. - Încercarea de a accesa o proprietate privată direct din afara clasei va genera o eroare.
Astfel, vizibilitatea (public, private) ajută la încapsulare, adică la protejarea datelor interne ale obiectelor și la controlul accesului.
Constructor & Destructor în PHP
În programarea orientată pe obiecte, constructorii și destructorii sunt metode speciale ale unei clase:
- Constructor (__construct) - se apelează automat când se creează un obiect. Este util pentru inițializarea proprietăților sau executarea unor acțiuni la momentul creării obiectului.
- Destructor (__destruct) - se apelează automat când obiectul este distrus sau scriptul se termină. Este folosit pentru curățarea resurselor, închiderea conexiunilor, etc.
Exemplu practic: constructor și destructor
<?php
class User {
public $name;
private $email;
// Constructor
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
echo "✅ Obiectul User a fost creat pentru $name.<br>";
}
// Destructor
public function __destruct() {
echo "🗑️ Obiectul User pentru $this->name a fost distrus.<br>";
}
public function getEmail() {
return $this->email;
}
}
// Creăm obiecte
$user1 = new User("Ion Popescu", "ion.popescu@example.com");
$user2 = new User("Maria Ionescu", "maria.ionescu@example.com");
// Accesăm email-ul prin metoda publică
echo "Email-ul lui $user1->name este: " . $user1->getEmail() . "<br>";
echo "Email-ul lui $user2->name este: " . $user2->getEmail() . "<br>";
// La finalul scriptului sau când obiectele sunt șterse, destructorul va fi apelat automat
?>
Observații:
- Constructorul (__construct) a fost apelat automat la crearea fiecărui obiect.
- Destructorul (__destruct) va fi apelat automat la sfârșitul scriptului sau când obiectele sunt distruse.
- Accesul la proprietăți private se face doar prin metode publice (ex:
getEmail()), demonstrând încapsularea.
Moștenire & Vizibilitate în PHP
În PHP, clasele pot moșteni proprietăți și metode din alte clase, ceea ce permite reutilizarea codului și extinderea funcționalităților. De asemenea, vizibilitatea definește accesul la proprietăți și metode:
- public - accesibil oriunde, în clasă, în subclase și din exterior;
- protected - accesibil în clasă și în subclase, dar nu din exterior;
- private - accesibil doar în clasa unde este definit.
Exemplu practic: moștenire și vizibilitate
<?php
// Clasa de bază (Parent)
class User {
public $name;
protected $role;
private $password;
public function __construct($name, $password) {
$this->name = $name;
$this->password = $password;
$this->role = "User";
}
public function getRole() {
return $this->role;
}
public function checkPassword($input) {
return $this->password === $input;
}
}
// Clasa copil (Child) care moștenește User
class Admin extends User {
public function __construct($name, $password) {
parent::__construct($name, $password);
$this->role = "Administrator"; // modificăm proprietatea protected
}
public function displayInfo() {
echo "<p>Nume: $this->name, Rol: $this->role</p>";
// Nu putem accesa $this->password direct, este private
}
}
// Creăm obiecte
$user = new User("Ion Popescu", "parola123");
$admin = new Admin("Maria Ionescu", "adminpass");
// Accesăm metode
echo "<p>Role User: " . $user->getRole() . "</p>";
echo "<p>Password corect? " . ($user->checkPassword("parola123") ? "✅" : "❌") . "</p>";
$admin->displayInfo();
?>
Observații:
- Clasa
Adminmoștenește toate proprietățile și metodele public/protected dinUser. - Proprietățile
privatenu sunt accesibile în subclasă. - Folosind vizibilitatea corectă, putem controla ce poate fi modificat sau accesat din exterior și ce trebuie să rămână protejat.
Interfaces & Traits în PHP
În PHP, Interfaces și Traits sunt instrumente puternice care ajută la organizarea codului și la reutilizarea funcționalităților fără moștenire clasică:
- Interface - definește un set de metode pe care orice clasă care implementează interfața trebuie să le aibă. Nu conține implementări, doar semnături.
- Trait - permite reutilizarea codului între mai multe clase, oferind implementări concrete de metode, fără a folosi moștenirea clasică.
Exemplu practic: Interface
<?php
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
public function log($message) {
echo "Salvat în fișier: $message<br>";
}
}
class DatabaseLogger implements Logger {
public function log($message) {
echo "Salvat în DB: $message<br>";
}
}
$fileLogger = new FileLogger();
$fileLogger->log("Mesaj test pentru fișier");
$dbLogger = new DatabaseLogger();
$dbLogger->log("Mesaj test pentru baza de date");
?>
Exemplu practic: Trait
<?php
trait Timestamp {
public function createdAt() {
return date("Y-m-d H:i:s");
}
}
class Post {
use Timestamp;
public $title;
public function __construct($title) {
$this->title = $title;
}
public function show() {
echo "<p>Post: $this->title (Creat la: " . $this->createdAt() . ")</p>";
}
}
$post = new Post("Primul articol");
$post->show();
?>
Observații:
- Interface-urile sunt excelente pentru a garanta că anumite metode există în clase diferite, fără a impune implementarea lor.
- Traits permit reutilizarea codului în mai multe clase fără să schimbăm ierarhia claselor.
- Putem combina moștenirea, interfaces și traits pentru a construi aplicații OOP flexibile și ușor de întreținut.
Namespace-uri în PHP
În aplicații mari, pot apărea conflicte între clase, funcții sau constante cu același nume. Namespace-urile ne permit să organizăm codul și să evităm aceste conflicte prin gruparea elementelor sub un "spațiu de nume" specific.
Sintaxa unui namespace
<?php
namespace App\Models;
class User {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function greet() {
echo "Salut, $this->name!<br>";
}
}
?>
Utilizarea unui namespace
<?php
require 'User.php'; // fișierul care conține clasa User cu namespace App\Models
// folosim clasa cu prefixul namespace-ului
$user = new App\Models\User("Ion Popescu");
$user->greet();
?>
Alias pentru namespace
<?php
use App\Models\User as AppUser;
$user = new AppUser("Maria Ionescu");
$user->greet();
?>
Observații:
- Namespace-urile permit organizarea codului pe module sau componente.
- Se evită conflictele de nume între clase cu aceeași denumire, de exemplu `User` în module diferite.
- Se pot crea alias-uri pentru a simplifica folosirea claselor din namespace-uri lungi.
Exemplu practic: User class + Database class
Acest exemplu arată cum să folosim OOP pentru a gestiona utilizatori într-o bază de date MySQL. Vom avea două clase: Database pentru conexiune și User pentru operațiile CRUD.
<?php
// Clasa pentru conexiunea la baza de date
class Database {
private $host = "localhost";
private $db = "traffice-test";
private $user = "root";
private $pass = "";
public $pdo;
public function __construct() {
try {
$this->pdo = new PDO("mysql:host={$this->host};dbname={$this->db}", $this->user, $this->pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("❌ Conexiune eșuată: " . $e->getMessage());
}
}
}
// Clasa User cu operații CRUD
class User {
private $db;
public function __construct($database) {
$this->db = $database->pdo;
}
public function create($name, $email) {
$stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute([':name' => $name, ':email' => $email]);
}
public function readAll() {
$stmt = $this->db->query("SELECT * FROM users");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function update($id, $name, $email) {
$stmt = $this->db->prepare("UPDATE users SET name=:name, email=:email WHERE id=:id");
$stmt->execute([':name' => $name, ':email' => $email, ':id' => $id]);
}
public function delete($id) {
$stmt = $this->db->prepare("DELETE FROM users WHERE id=:id");
$stmt->execute([':id' => $id]);
}
}
// Instanțiem baza de date și clasa User
$db = new Database();
$user = new User($db);
// Exemplu de adăugare utilizator (poți folosi formular HTML mai jos)
if (isset($_POST['create'])) {
$user->create($_POST['name'], $_POST['email']);
}
// Exemplu de update
if (isset($_POST['update'])) {
$user->update($_POST['id'], $_POST['name'], $_POST['email']);
}
// Exemplu de delete
if (isset($_POST['delete'])) {
$user->delete($_POST['id']);
}
// Citim toți utilizatorii pentru afișare
$users = $user->readAll();
?>
Formular simplu CRUD
<form method="post">
<h4>Adaugă utilizator</h4>
Nume: <input type="text" name="name" required>
Email: <input type="email" name="email" required>
<button type="submit" name="create">Adaugă</button>
</form>
<h4>Lista utilizatori</h4>
<table border="1" cellpadding="5">
<tr><th>ID</th><th>Nume</th><th>Email</th><th>Acțiuni</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<form method="post">
<td><?php echo $u['id']; ?></td>
<td><input type="text" name="name" value="<?php echo htmlspecialchars($u['name']); ?>"></td>
<td><input type="email" name="email" value="<?php echo htmlspecialchars($u['email']); ?>"></td>
<td>
<input type="hidden" name="id" value="<?php echo $u['id']; ?>">
<button type="submit" name="update">Update</button>
<button type="submit" name="delete">Delete</button>
</td>
</form>
</tr>
<?php endforeach; ?>
</table>
<?php
// Clasa pentru conexiunea la baza de date
class Database {
private $host = "localhost";
private $db = "traffice-test";
private $user = "traffice_php";
private $pass = "!@y3Ge-Z!WQI";
public $pdo;
public function __construct() {
try {
$this->pdo = new PDO("mysql:host={$this->host};dbname={$this->db}", $this->user, $this->pass);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("❌ Conexiune eșuată: " . $e->getMessage());
}
}
}
// Clasa User cu operații CRUD
class User {
private $db;
public function __construct($database) {
$this->db = $database->pdo;
}
public function create($name, $email) {
$stmt = $this->db->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute([':name' => $name, ':email' => $email]);
}
public function readAll() {
$stmt = $this->db->query("SELECT * FROM users");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function update($id, $name, $email) {
$stmt = $this->db->prepare("UPDATE users SET name=:name, email=:email WHERE id=:id");
$stmt->execute([':name' => $name, ':email' => $email, ':id' => $id]);
}
public function delete($id) {
$stmt = $this->db->prepare("DELETE FROM users WHERE id=:id");
$stmt->execute([':id' => $id]);
}
}
// Instanțiem baza de date și clasa User
$db = new Database();
$user = new User($db);
// Exemplu de adăugare utilizator (poți folosi formular HTML mai jos)
if (isset($_POST['create'])) {
$user->create($_POST['name'], $_POST['email']);
}
// Exemplu de update
if (isset($_POST['update'])) {
$user->update($_POST['id'], $_POST['name'], $_POST['email']);
}
// Exemplu de delete
if (isset($_POST['delete'])) {
$user->delete($_POST['id']);
}
// Citim toți utilizatorii pentru afișare
$users = $user->readAll();
?>
<form method="post">
<h4>Adaugă utilizator</h4>
Nume: <input type="text" name="name" required>
Email: <input type="email" name="email" required>
<button type="submit" name="create">Adaugă</button>
</form>
<h4>Lista utilizatori</h4>
<table border="1" cellpadding="5">
<tr><th>ID</th><th>Nume</th><th>Email</th><th>Acțiuni</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<form method="post">
<td><?php echo $u['id']; ?></td>
<td><input type="text" name="name" value="<?php echo htmlspecialchars($u['name']); ?>"></td>
<td><input type="email" name="email" value="<?php echo htmlspecialchars($u['email']); ?>"></td>
<td>
<input type="hidden" name="id" value="<?php echo $u['id']; ?>">
<button type="submit" name="update">Update</button>
<button type="submit" name="delete">Delete</button>
</td>
</form>
</tr>
<?php endforeach; ?>
</table>
🧠 Quiz - OOP în PHP