Εν συντομία: Ο αντικειμενοστρεφής προγραμματισμός (OOP) συγκεντρώνει δεδομένα και τις αντίστοιχες συναρτήσεις σε κλάσεις. Η PHP προσφέρει γι' αυτό κλάσεις, αφηρημένες κλάσεις, διεπαφές, traits και, από την PHP 8.1, enums. Με τις PHP 8.0 έως 8.4 προστέθηκαν πολλά γλωσσικά μέσα, όπως το constructor promotion, το readonly, τα property hooks και η ασύμμετρη ορατότητα. Σημαντικό για την ασφάλεια: ένας καλά ενθυλακωμένος κώδικας ελέγχεται ευκολότερα και οι μαγικές μέθοδοι κάνουν επικίνδυνη την ανασφαλή αποσειριοποίηση. Απέναντι σε ευπάθειες του διερμηνέα, όπως το PHP2Shell, η OOP δεν βοηθά.
Τι σημαίνει αντικειμενοστρεφής προγραμματισμός στην PHP
Αντί για χαλαρές συναρτήσεις και καθολικές μεταβλητές, μια κλάση περιγράφει ένα πράγμα του επιχειρησιακού κόσμου: μια παραγγελία, έναν πελάτη, ένα τιμολόγιο. Ορίζει ποια δεδομένα το αποτελούν (ιδιότητες) και τι μπορεί να γίνει με αυτά (μέθοδοι). Ένα αντικείμενο είναι ένα συγκεκριμένο στιγμιότυπο αυτής της κλάσης.
Για όσους αποφασίζουν αυτό έχει πρακτική αξία: ένας αντικειμενοστρεφής κώδικας με σαφείς κλάσεις δοκιμάζεται, ελέγχεται και παραδίδεται σε παρόχους ευκολότερα. Οι παλιές εφαρμογές PHP που αποτελούνται από πολλά μεμονωμένα σενάρια με καθολικές μεταβλητές είναι αντίθετα δύσκολο να συντηρηθούν και επιρρεπείς σε σφάλματα κατά τις αναβαθμίσεις.
Μια κεντρική ιδέα είναι η ενθυλάκωση: μια κλάση εκθέτει προς τα έξω μόνο τις μεθόδους που οι άλλοι πραγματικά χρειάζονται και προστατεύει την εσωτερική της κατάσταση. Μια παραγγελία μπορεί τότε, για παράδειγμα, να σημανθεί ως πληρωμένη μόνο μέσω μιας μεθόδου που ελέγχει προηγουμένως αν αυτό επιτρέπεται. Η συγκέντρωση τέτοιων κανόνων σε ένα σημείο αποτελεί κέρδος και για την ασφάλεια.
Τα δομικά στοιχεία με μια ματιά
| Δομικό στοιχείο | Σκοπός | Σύντομο παράδειγμα |
|---|---|---|
| Κλάση | σχέδιο για αντικείμενα με ιδιότητες και μεθόδους | class Rechnung { ... } |
| αφηρημένη κλάση | κοινή βάση, δεν δημιουργεί απευθείας στιγμιότυπο | abstract class Zahlart { ... } |
| Διεπαφή | σύμβαση: ποιες μεθόδους πρέπει να προσφέρει μια κλάση | interface Versandfaehig { ... } |
| Trait | επαναχρησιμοποιήσιμες μέθοδοι για κλάσεις χωρίς κοινή γονική κλάση | trait MitZeitstempel { ... } |
| Enum | σταθερό σύνολο επιτρεπτών τιμών ως δικός τους τύπος, από την PHP 8.1 | enum Status { case Offen; ... } |
Οι ορατότητες (public, protected, private) ρυθμίζουν ποιος επιτρέπεται να προσπελαύνει ιδιότητες και μεθόδους. Οι κλάσεις οργανώνονται σε namespaces και φορτώνονται μέσω ενός autoloader· πώς λειτουργεί αυτό, δείχνει η σελίδα Namespaces και autoloading.
Σύγχρονη PHP: οι καινοτομίες από την 8.0 ως την 8.4
Τα παρακάτω γλωσσικά μέσα τεκμηριώνονται στο εγχειρίδιο της PHP ή στις ανακοινώσεις των εκδόσεων:
| Έκδοση | Καινοτομία |
|---|---|
| 8.0 | Constructor promotion, τελεστής nullsafe ?->, ::class σε αντικείμενα |
| 8.1 | ιδιότητες readonly, enums, new σε αρχικοποιητές, final για σταθερές κλάσεων |
| 8.2 | κλάσεις readonly· οι δυναμικές ιδιότητες θεωρούνται παρωχημένες |
| 8.3 | χαρακτηριστικό #[\Override], τυποποιημένες σταθερές κλάσεων |
| 8.4 | Property hooks, ασύμμετρη ορατότητα, new χωρίς περιβάλλουσες παρενθέσεις |
Ένα παράδειγμα που συνδυάζει πολλά από αυτά τα μέσα:
<?php
declare(strict_types=1);
enum Status: string
{
case Offen = 'offen';
case Bezahlt = 'bezahlt';
}
final class Bestellung
{
public function __construct(
public readonly int $id,
public private(set) Status $status = Status::Offen, // από την PHP 8.4
) {}
public function alsBezahltMarkieren(): void
{
$this->status = Status::Bezahlt;
}
}
$b = new Bestellung(42);
$b->alsBezahltMarkieren();
echo $b->status->value; // bezahlt
$s = Status::tryFrom('storniert'); // null αντί για σφάλμα
Το readonly αποτρέπει την αλλαγή του αναγνωριστικού μετά τη δημιουργία. Το private(set) επιτρέπει την ανάγνωση από έξω, την εγγραφή όμως μόνο μέσα στην κλάση. Τέτοιες διασφαλίσεις στον κώδικα κάνουν λιγότερο πιθανά τα σφάλματα που αλλιώς γίνονται αντιληπτά μόνο κατά τη λειτουργία. Τους τύπους πίσω από αυτά εξηγεί η σελίδα Το σύστημα τύπων της PHP.
Παγίδες αναβάθμισης στον αντικειμενοστρεφή κώδικα
Για τις παλαιότερες εφαρμογές δύο αλλαγές είναι ιδιαίτερα σημαντικές. Από την PHP 8.2.0 η δημιουργία δυναμικών ιδιοτήτων, δηλαδή ιδιοτήτων που δεν έχουν δηλωθεί στην κλάση, θεωρείται παρωχημένη, εκτός αν η κλάση φέρει το χαρακτηριστικό #[\AllowDynamicProperties]. Ο παλαιότερος κώδικας το κάνει αυτό συχνά ασυναίσθητα και γεμίζει έτσι τα logs με υποδείξεις. Επιπλέον, οι τυποποιημένες ιδιότητες πρέπει σύμφωνα με το εγχειρίδιο να έχουν αρχικοποιηθεί πριν από την πρώτη ανάγνωση, διαφορετικά η PHP πετά ένα Error.
Χρήσιμο είναι το χαρακτηριστικό #[\Override] της PHP 8.3: σημαίνει μια μέθοδο ως υπέρβαση μιας γονικής μεθόδου. Αν αυτή η μέθοδος δεν υπάρχει πια, για παράδειγμα μετά από μετονομασία σε μια βιβλιοθήκη, η PHP αναφέρει σφάλμα αντί να αφήσει τη μέθοδο σιωπηλά να λειτουργεί στο κενό. Τέτοιοι έλεγχοι κάνουν τις αναβαθμίσεις προβλέψιμες· στα κολλημένα παλιά έργα βοηθά η μετάβασή μας σε υποστηριζόμενη έκδοση PHP.
Αντικείμενα και μνήμη
Τα αντικείμενα μεταβιβάζονται στην PHP μέσω αναγνωριστικών (handles). Όταν ένα αντικείμενο δίνεται σε μια συνάρτηση, αυτή εργάζεται με το ίδιο αντικείμενο, όχι με αντίγραφο. Αυτό είναι αποδοτικό, οδηγεί όμως εύκολα σε κυκλικές αναφορές, για παράδειγμα όταν μια παραγγελία γνωρίζει τις θέσεις της και κάθε θέση γνωρίζει ξανά την παραγγελία της. Τέτοιους κύκλους δεν τους καθαρίζει μόνη της η μέτρηση αναφορών· γι' αυτό η PHP διαθέτει δικό της garbage collector. Λεπτομέρειες υπάρχουν στη σελίδα Διαχείριση μνήμης στην PHP.
OOP και ασφάλεια: μαγικές μέθοδοι και αποσειριοποίηση
Η PHP γνωρίζει μαγικές μεθόδους που καλούνται αυτόματα, όπως οι __construct, __destruct, __toString, __get ή __wakeup. Αυτό είναι πρακτικό, έχει όμως και μια σκοτεινή πλευρά: όταν μια εφαρμογή μετατρέπει ξένα δεδομένα ξανά σε αντικείμενα με την unserialize(), ένας επιτιθέμενος μπορεί να καθορίσει ποιες κλάσεις δημιουργούνται και έτσι να πυροδοτήσει υπάρχοντα κώδικα σε μαγικές μεθόδους. Πώς αποτρέπεται αυτό, περιγράφει ο οδηγός Ανασφαλής αποσειριοποίηση στην PHP. Εν ολίγοις: για την ανταλλαγή δεδομένων χρησιμοποιήστε τις json_encode() και json_decode() και την unserialize() μόνο για δικά σας, αξιόπιστα δεδομένα, ιδανικά με την επιλογή allowed_classes.
Στο PHP2Shell, αντίθετα, ο καλός αντικειμενοστρεφής κώδικας δεν βοηθά. Οι CVE-2026-109618 και CVE-2026-109619 βρίσκονται στον διερμηνέα και, σύμφωνα με την ομάδα της PHP, στο mod_php έχει επιδειχθεί exploit πριν εκτελεστεί ο κώδικας της εφαρμογής. Υποχρεωτικές είναι η ενημέρωση στην PHP 8.5.12, 8.4.27, 8.3.36 ή 8.2.35 και η επανεκκίνηση όλων των διεργασιών PHP.
Πώς βοηθά συγκεκριμένα η PHP SOS;
- Αξιολογούμε τη δομή της εφαρμογής σας και δείχνουμε ποια τμήματα δυσκολεύουν την αναβάθμιση σε υποστηριζόμενη έκδοση PHP.
- Αναζητούμε στοχευμένα επικίνδυνα μοτίβα, όπως η
unserialize()σε ξένα δεδομένα και επικίνδυνες μαγικές μεθόδους. - Ελέγχουμε τις εσωτερικές ανεπτυγμένες λύσεις στο πλαίσιο ενός ελέγχου ασφαλείας και δοκιμής διείσδυσης.
- Εγκαθιστούμε την ενημέρωση της PHP, επανεκκινούμε όλους τους workers και δοκιμάζουμε στη συνέχεια την εφαρμογή.
Συχνές ερωτήσεις
Είναι η PHP αντικειμενοστρεφής γλώσσα;
Η PHP υποστηρίζει τόσο διαδικαστικό όσο και αντικειμενοστρεφή κώδικα. Τα frameworks, οι πυρήνες των CMS και τα συστήματα ηλεκτρονικών καταστημάτων είναι σήμερα όμως κατά κύριο λόγο αντικειμενοστρεφή, με κλάσεις, διεπαφές και namespaces.
Ποια είναι η διαφορά μεταξύ διεπαφής και αφηρημένης κλάσης;
Μια διεπαφή περιγράφει μόνο ποιες μεθόδους πρέπει να προσφέρει μια κλάση. Μια αφηρημένη κλάση μπορεί επιπλέον να περιέχει ήδη κώδικα και ιδιότητες, αλλά δεν μπορεί να δημιουργήσει απευθείας στιγμιότυπο. Μια κλάση μπορεί να έχει περισσότερες διεπαφές, αλλά μόνο μία γονική κλάση.
Από πότε υπάρχουν τα enums στην PHP;
Οι απαριθμήσεις (enumerations) ήρθαν με την PHP 8.1. Αντικαθιστούν τις συλλογές σταθερών με έναν δικό τους τύπο, που επιτρέπει μόνο τις ορισμένες περιπτώσεις. Τα backed enums έχουν επιπλέον μια τιμή int ή string.
Γιατί οι μαγικές μέθοδοι είναι σημαντικές για την ασφάλεια;
Μεθόδους όπως οι __destruct ή __wakeup τις καλεί αυτόματα η PHP, για παράδειγμα κατά την αποσειριοποίηση δεδομένων. Αν ξένα δεδομένα φτάσουν αδιάκριτα στην unserialize(), αυτό μπορεί να πυροδοτήσει απροσδόκητες ροές σε υπάρχουσες κλάσεις.