Image for Post:

Se lavori con PHP e WordPress da un po’ di tempo, prima o poi ti sarai imbattuto in una domanda che all’inizio sembra semplice, ma che nella pratica si rivela molto più sfumata: le nuove funzionalità è meglio svilupparle con classi o con funzioni?

Per me non si tratta solo di una discussione teorica. È un argomento che ogni tanto emerge anche nei colloqui, quando mi chiedono quale stile di sviluppo preferisco. E la mia risposta sincera è sempre la stessa: non credo che tutto debba essere sviluppato necessariamente con classi, ma non penso nemmeno che il codice funzionale sia sempre la scorciatoia migliore. Nei progetti reali, questo tipo di ragionamento troppo rigido raramente aiuta.

Scrivere tutto con classi PHP solo perché “sembra più professionale” non è sempre la scelta giusta. Allo stesso modo, ridurre tutto a semplici funzioni solo perché è più veloce non è sempre la decisione più intelligente. La scelta giusta dipende dalla funzionalità concreta che stai sviluppando, dalla sua prospettiva futura, dal budget, dalle tempistiche e dalla probabilità che quel codice debba crescere o essere esteso in seguito.

Per me, è proprio questo il segno di un approccio maturo allo sviluppo.

Da cosa dovrebbe dipendere questa scelta?

Prima di scrivere qualsiasi riga di codice, vale la pena fermarsi e porsi alcune domande pratiche.

1. Quanto è grande e complessa la funzionalità?

Se si tratta di una piccola modifica, di un singolo hook, di una o due funzioni helper o di una semplice integrazione senza reali prospettive di crescita, di solito non ha molto senso costruire attorno a tutto questo un’architettura completa basata su classi, servizi separati, registrar e container.

Ma se la funzionalità comprende elementi come:

  • più entità correlate;

  • impostazioni dedicate;

  • pagine di amministrazione;

  • endpoint REST API;

  • integrazioni con servizi esterni;

  • validazione;

  • diversi scenari d’uso;

allora il codice smette molto rapidamente di essere “piccolo”. Ed è proprio a questo punto che una struttura basata su classi inizia davvero ad avere senso.

2. È probabile che questa funzionalità evolva?

Questa è una delle domande più importanti. Molte funzionalità all’inizio sembrano semplici. Ma se già sai che:

  • in futuro verranno aggiunte nuove caratteristiche;

  • la logica potrebbe cambiare;

  • il progetto è pensato per durare nel tempo;

  • il cliente tende a chiedere miglioramenti anche dopo il rilascio;

allora la manutenibilità dovrebbe entrare nella decisione fin da subito, e non diventare un problema da affrontare più avanti.

3. Quali sono budget e tempi disponibili?

A volte un’azienda ha bisogno di una soluzione subito. A volte il budget è limitato. In questi casi, un’architettura troppo pesante potrebbe semplicemente non valere il tempo extra che richiede.

Se la funzionalità è piccola e la scadenza è stretta, un approccio funzionale può essere la scelta più pragmatica.

Detto questo, è importante non confondere una soluzione rapida con una soluzione disordinata. Anche il codice funzionale può essere scritto in modo pulito, prevedibile e sufficientemente facile da mantenere, se viene fatto con attenzione.

4. Chi manterrà il codice in futuro?

Se è probabile che quel codice resti nel progetto per anni e venga toccato anche da altri sviluppatori, allora la struttura conta molto di più. In queste situazioni, le classi spesso hanno un vantaggio perché rendono più facile separare responsabilità, logica e punti di ingresso.

5. Dove vivrà esattamente questa funzionalità?

C’è una grande differenza tra:

  • un piccolo snippet dentro un tema;

  • un modulo autonomo;

  • un mu-plugin;

  • un plugin personalizzato;

  • una grande integrazione che comunica con più servizi esterni.

Più il codice è indipendente e più a lungo è destinato a vivere al di fuori del tema, più diventa utile investire in una buona struttura.

Quando un approccio basato su classi è davvero la scelta giusta

Image: When Structure Starts Paying OffNel contesto di WordPress e dello sviluppo PHP personalizzato, questo approccio si allinea bene anche con le raccomandazioni dell’official WordPress Plugin Handbook, che menziona l’object-oriented method, la file organization e la plugin architecture come modelli utili per soluzioni più complesse e di lungo periodo.

Il punto di forza principale delle classi non è che siano automaticamente migliori. È che spesso sono più adatte a codice destinato a crescere, cambiare e richiedere manutenzione nel tempo.

Cosa offre una struttura basata su classi

Per progetti come un aggregatore di notizie regionali, dove bisogna lavorare con molte fonti, API, cron job, elaborazione dei dati, caching, logging e sviluppo continuo di nuove funzionalità, un approccio basato su classi è spesso molto più facile da giustificare. In sistemi di questo tipo, l’obiettivo non è solo rilasciare rapidamente la prima versione, ma avere una struttura che possa essere mantenuta, estesa e migliorata nel tempo. È facile immaginare questa esigenza in un progetto come Kutok.media, dove vengono aggregate notizie regionali provenienti da diverse aree dell’Ucraina.

Struttura migliore

Quando la logica è divisa in classi, diventa molto più semplice capire dove si trova ogni cosa:

  • la registrazione degli hook in un punto;

  • la logica API in un altro;

  • la validazione separata;

  • la gestione dei dati separata;

  • l’interfaccia amministrativa gestita in modo indipendente.

Questo riduce il rischio di trasformare il progetto in un unico file enorme pieno di funzioni, dove ogni modifica futura diventa sempre più difficile da trovare e sempre più rischiosa da fare.

Scalabilità migliore

Quando la funzionalità cresce, le classi rendono più facile estendere il codice in modo prevedibile. Puoi aggiungere servizi, moduli, classi per le impostazioni, logger, livelli di integrazione ed event handler senza infilare tutto nello stesso flusso procedurale.

Nei progetti più grandi questo diventa sempre più importante, perché la manutenzione conta quanto l’implementazione iniziale.

Più facile aggiornare il codice esistente

Nei progetti di lunga durata, il codice raramente viene scritto una volta sola e poi lasciato intatto per sempre. Più spesso viene ampliato, adattato e rielaborato.

Quando la logica è organizzata in classi, diventa più facile:

  • isolare le modifiche;

  • evitare di toccare parti non correlate;

  • testare componenti specifici;

  • ridurre la duplicazione.

Minore rischio di conflitti

Questo conta anche in WordPress. Le funzioni globali hanno molte più probabilità di entrare in conflitto, soprattutto nei progetti grandi o nei codebase con più moduli custom. Classi e namespace aiutano a ridurre questo rischio e rendono il codice più sicuro da estendere.

Migliore per il lavoro in team

Quando su uno stesso progetto lavorano più sviluppatori, il codice basato su classi è generalmente più semplice da capire e mantenere. Per chi entra nuovo nel progetto è molto più facile seguire l’architettura, rispetto a un codice sparso tra functions.php, helpers.php e altri file custom poco collegati tra loro.

Gli svantaggi delle classi

Naturalmente esistono anche compromessi reali.

Avvio più lento

Per i task più piccoli, una soluzione basata su classi richiede quasi sempre più tempo all’inizio:

  • creare i file;

  • progettare la struttura;

  • registrare le classi;

  • collegare l’inizializzazione;

  • ragionare sulle dipendenze.

A volte questo tempo extra è giustificato. A volte no.

Più codice di supporto

Una parte del codice basato su classi non è logica di business, ma solo struttura e setup. Per i task piccoli, questo può sembrare un sovraccarico inutile.

È facile esagerare con l’architettura

A volte gli sviluppatori costruiscono l’architettura di un grande prodotto quando in realtà serve solo una piccola funzionalità pratica. Il risultato può sembrare impressionante, ma non sempre genera un reale valore per il cliente o per il business.

Quindi le classi non sono intrinsecamente la soluzione migliore. Sono semplicemente più adatte quando la complessità e la crescita nel lungo periodo lo richiedono davvero.

Quando l’approccio funzionale ha più senso

Allo stesso tempo, PHP supporta naturalmente uno stile funzionale attraverso le user-defined functions, i callback, le funzioni anonime e altre caratteristiche di base del linguaggio. Questo significa che usare funzioni per funzionalità piccole e localizzate non è una scorciatoia né un compromesso: è un modo assolutamente valido di sviluppare.

Il codice funzionale viene spesso sottovalutato, come se fosse in qualche modo meno serio o meno professionale. In realtà, ci sono molti casi in cui è l’opzione più adatta.

Dove l’approccio funzionale funziona particolarmente bene

Funzionalità piccole e locali

Se devi:

  • aggiungere qualche hook;

  • modificare il comportamento di un template;

  • creare un piccolo handler AJAX;

  • aggiungere una semplice integrazione;

  • fare un intervento mirato;

allora le funzioni semplici spesso ti permettono di ottenere il risultato più in fretta e con molto meno overhead.

Progetti con budget limitato

Non tutti i progetti hanno un grande budget, e non tutti i clienti sono disposti a pagare per un’architettura costruita pensando a un futuro che magari non arriverà mai.

In queste situazioni, un approccio funzionale spesso aiuta a:

  • consegnare più velocemente;

  • mantenere sotto controllo i costi;

  • evitare ore extra spese in struttura e scaffolding;

  • realizzare una soluzione pratica entro i vincoli del progetto.

Funzionalità senza reali prospettive di crescita

A volte è chiaro fin dall’inizio che la funzionalità:

  • non crescerà;

  • non diventerà un modulo autonomo;

  • non richiederà manutenzione complessa;

  • è sostanzialmente una piccola utility limitata.

In questi casi, usare funzioni è una scelta del tutto sana e sensata.

Vantaggi dell’approccio funzionale

Implementazione più veloce

Questo è il vantaggio principale. Le piccole funzionalità in genere si implementano molto più rapidamente con un approccio funzionale.

Semplicità

Quando la logica è breve e lineare, avvolgerla in un’architettura più pesante spesso aggiunge più formalità che valore. Per un task piccolo, una funzione ben scritta può tranquillamente essere migliore di tre classi.

Soglia di ingresso più bassa

Questo tipo di codice è anche più facile da leggere rapidamente, soprattutto in progetti dove il team o il cliente non hanno interesse a investire in una struttura architetturale più pesante.

Gli svantaggi dell’approccio funzionale

Anche questo approccio, però, inizia a mostrare i suoi limiti quando il codebase cresce.

Più difficile da scalare in modo pulito

Quando si aggiunge più funzionalità, aumentano anche i rischi:

  • logica duplicata;

  • responsabilità mescolate;

  • fix temporanei che si accumulano;

  • file troppo grandi e sempre più difficili da gestire.

Problemi di namespace globale

In WordPress questo è particolarmente evidente. Senza prefissi coerenti e una struttura chiara, è facile ritrovarsi con conflitti di nomi o con una generale mancanza di ordine.

La manutenzione può diventare più costosa in seguito

Quello che fa risparmiare tempo all’inizio può facilmente costare di più nel lungo periodo. Per questo l’approccio funzionale è più adatto quando non c’è alcuna vera aspettativa di crescita futura.

Una nota sui plugin personalizzati

Per me la regola qui è abbastanza semplice: se un plugin personalizzato non è estremamente piccolo e one-off, di solito conviene svilupparlo fin dall’inizio con classi.

Perché?

Perché un plugin non è solo un po’ di logica dentro un tema. È un’unità separata che:

  • ha il proprio ciclo di vita;

  • può essere aggiornata;

  • può crescere nel tempo;

  • può essere riutilizzata in altri progetti;

  • spesso sopravvive più a lungo del tema con cui è nato.

Anche se all’inizio il plugin è piccolo, se c’è una ragionevole probabilità che in futuro debba includere:

  • una pagina impostazioni;

  • ruoli personalizzati;

  • route REST API;

  • cron task;

  • integrazioni con servizi esterni;

  • logging;

  • più schermate di amministrazione;

allora una struttura basata su classi è di solito la scelta più lungimirante.

Per plugin molto piccoli e puramente utilitari, ovviamente possono esserci eccezioni. Se un plugin fa una sola cosa semplice e con ogni probabilità non crescerà, un approccio funzionale può andare benissimo. Ma nel momento in cui la crescita diventa probabile, il codice procedurale dentro un plugin tende a diventare difficile da mantenere piuttosto in fretta.

Un confronto approssimativo in numeri

comparative graphicsÈ importante essere onesti: non esistono numeri universalmente esatti. Tutto dipende dal task, dallo sviluppatore, dai requisiti del progetto e da quanta architettura si sta introducendo.

Detto questo, sulla base dell’esperienza pratica, le stime approssimative spesso assomigliano a queste.

Per nuove funzionalità piccole:

  • implementazione iniziale con classi: circa 20–45% più lenta;

  • dimensione del codice: spesso 25–60% di righe in più;

  • numero di file: di solito 2–4 volte maggiore;

  • modifiche future: possono diventare in media 15–35% più veloci se la funzionalità cresce.

Per un modulo medio o di lungo periodo:

  • iniziare con classi può richiedere 25–50% di tempo in più;

  • ma dopo vari cicli di aggiunte e modifiche, la struttura a classi spesso inizia a far risparmiare tempo;

  • nel lungo periodo, la manutenzione può risultare 20–40% più semplice rispetto a una soluzione funzionale costruita in modo poco strutturato.

In molti casi, quindi, il codice funzionale vince all’inizio, mentre quello basato su classi vince nel tempo, se la funzionalità continua davvero a evolvere.

Un semplice esempio di codice

Vediamo un esempio molto semplice: aggiungere un endpoint REST personalizzato in WordPress che restituisce una lista di post.

Versione funzionale


<?php add_action('rest_api_init', 'km_register_posts_endpoint'); function km_register_posts_endpoint() { register_rest_route('km/v1', '/posts', array( 'methods' => 'GET',
        'callback' => 'km_get_posts_endpoint',
        'permission_callback' => '__return_true',
    ));
}

function km_get_posts_endpoint(WP_REST_Request $request) {
    $posts = get_posts(array(
        'post_type'      => 'post',
        'posts_per_page' => 5,
        'post_status'    => 'publish',
    ));

    $data = array();

    foreach ($posts as $post) {
        $data[] = array(
            'id'    => $post->ID,
            'title' => get_the_title($post->ID),
            'link'  => get_permalink($post->ID),
        );
    }

    return rest_ensure_response($data);
}

Vantaggi

  • veloce da scrivere;

  • numero minimo di file;

  • facile da capire per un task piccolo;

  • perfettamente sufficiente per funzionalità limitate.

Svantaggi

  • se in futuro la funzionalità cresce includendo più endpoint, validazione, caching, logging e logica di permessi, il codice può diventare rapidamente disordinato;

  • scalarlo in modo pulito diventa più difficile col tempo.

Versione basata su classi


<?php class KM_Posts_API { public function init() { add_action('rest_api_init', array($this, 'register_routes')); } public function register_routes() { register_rest_route('km/v1', '/posts', array( 'methods' => 'GET',
            'callback'            => array($this, 'get_posts'),
            'permission_callback' => array($this, 'permissions_check'),
        ));
    }

    public function permissions_check(WP_REST_Request $request) {
        return true;
    }

    public function get_posts(WP_REST_Request $request) {
        $posts = get_posts(array(
            'post_type'      => 'post',
            'posts_per_page' => 5,
            'post_status'    => 'publish',
        ));

        $data = array();

        foreach ($posts as $post) {
            $data[] = array(
                'id'    => $post->ID,
                'title' => get_the_title($post->ID),
                'link'  => get_permalink($post->ID),
            );
        }

        return rest_ensure_response($data);
    }
}

$km_posts_api = new KM_Posts_API();
$km_posts_api->init();

Vantaggi

  • la logica ha già una struttura chiara;

  • aggiungere nuovi metodi è semplice;

  • permessi, validazione, formattazione e logica dei servizi sono più facili da separare;

  • è molto più semplice da estendere in futuro.

Svantaggi

  • per un task molto piccolo richiede più tempo e aggiunge più peso;

  • c’è più codice di struttura;

  • non sempre vale la pena nei task minori.

La conclusione a cui sono arrivato

Nella mia esperienza, i clienti di solito non capiscono — e francamente non hanno nemmeno bisogno di capire — quale approccio tecnico sia migliore. Ciò che per loro conta è molto più semplice:

  • funzionerà?

  • quanto costerà?

  • quanto tempo richiederà?

  • si potrà modificare in futuro?

Per questo, la responsabilità della scelta ricade sullo sviluppatore.

E questo significa che non basta semplicemente “avere uno stile preferito”. Un buon sviluppatore deve saper fare le domande giuste per capire il bisogno reale dietro la richiesta:

  • questa funzionalità è destinata a crescere?

  • dovrà scalare?

  • esiste un budget per una struttura più flessibile?

  • quanto è importante la velocità della prima consegna?

  • chi si occuperà della manutenzione tra sei mesi?

Se scegli un approccio basato su classi, dovresti essere pronto a spiegarlo chiaramente. Non nel senso di dire “è più corretto così”, ma in termini comprensibili per il business:

  • richiede più tempo adesso, ma costerà meno da mantenere in futuro;

  • crea una struttura utile per le modifiche successive;

  • riduce il caos se il modulo cresce.

Se invece la funzionalità è piccola, locale, guidata dal budget e poco probabile che evolva, allora una soluzione funzionale è spesso la scelta più onesta e pratica.

Per me, la conclusione principale è semplice:

la vera domanda non è se siano migliori le classi o le funzioni. La vera domanda è quale delle due soluzioni sia più adatta al lavoro specifico da fare.

Uno sviluppatore forte non è quello che impone sempre lo stesso approccio ovunque. È quello che sa scegliere lo strumento giusto per il compito che ha davanti.