2015-01-23 12 views
9

Sto utilizzando Codeigniter e Composer. Uno dei requisiti è PHPExcel. Ora ho bisogno di cambiare una funzione in una delle classi. Quale dovrebbe essere la migliore strategia per farlo? Devo cambiare il codice nella cartella del venditore? In tal caso, come mantenere la modifica su tutte le istanze? In caso contrario, come sovrascrivere quella particolare classe. Sebbene io menzioni PHPExcel, vorrei una soluzione generica.Strategia per sovrascrivere una classe in una libreria installata con Composer

Non sono sicuro se questo è il forum giusto per questa domanda. Se non lo rimuoverò. Per favore fatemi sapere se sono necessari ulteriori dettagli.

Grazie.

+0

Oh sì, PHPExcel, lo stesso motivo per essere qui. – Luke

risposta

15

In composer.json, sotto [ "autoload"] [ "PSR-4"], aggiungere una voce con namespace come la chiave e il percorso come valore:

{ 
    "autoload": { 

     "psr-4": { 

      "BuggyVendor\\Namespace\\": "myfixes/BuggyVendor/Namespace" 
     } 
    } 
} 

Copiare i file che si desidera sovrascrivere sotto quel percorso (mantenendo la struttura di directory del sottospazio) e modificateli lì. Verranno scelti in base al "classpath" originale del pacchetto della libreria. Sembrerebbe che i namespace-> path mapping aggiunti a composer.json in questo modo siano considerati prima di quelli aggiunti dai pacchetti richiesti. Nota: l'ho appena provato e ha funzionato, anche se non so se si tratti di una funzione prevista o di possibili trucchi.

MODIFICA: trovato un gotcha. A volte, quando successivamente richiedi un altro pacchetto con composer require vendor/package, perderai l'override. Se ciò accade, è necessario emettere composer dump-autoload manualmente. Questo ripristinerà il corretto ordine di caricamento automatico rispettando il tuo override.

+0

Sei davvero eccezionale. Ho cercato di trovare un modo per scavalcare l'orribile EntityGenerator di Doctrine e mi hai dato esattamente quello di cui avevo bisogno. Sei un EROE. –

+5

Usando questo approccio probabilmente otterrai qualcosa del tipo: '' ' Attenzione: risoluzione della classe ambigua," Doctrine \ Common \ Collections \ ArrayCollection "trovata in" vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php "e" src \ Doctrine \ Common \ Collections \ ArrayCollection.php ", il primo verrà utilizzato. '' ' Per ovviare a questo problema aggiungere classe originale di esclusione: ' '' "escludere-da-classmap": [ "vendor/doctrine/collezioni/lib/doctrine/comune/Collezioni/ArrayCollection.php"] '' ', e quindi il caricatore automatico risolverà la classe di override. –

+0

@OlegAndreyev Questa dovrebbe essere una risposta a parte. Questo è stato molto utile e una soluzione esattamente al mio problema. Grazie mille! –

-3

La modifica di una classe esistente è contraria ai principi OOP e SOLID (Apri per estensione/Chiusa per principio di modifica in modo specifico). Quindi la soluzione qui non è di cambiare il codice direttamente, ma di estendere il codice per aggiungere la tua funzionalità.

In un mondo ideale non si dovrebbe mai cambiare un pezzo di codice che non si possiede. Infatti, con il compositore non è possibile perché la modifica verrà annullata durante l'aggiornamento delle dipendenze.

Una soluzione nel tuo caso è creare una classe a livello di applicazione ed estendere la classe che desideri modificare (che è a livello di libreria) per sovrascrivere il tuo codice. Si prega di guardare estendere una classe in PHP se non si sa come.

Quindi, in genere, si carica la classe anziché la propria classe, in questo modo si aggiunge la propria funzionalità oltre alla loro funzionalità e, in caso di un aggiornamento, non si interrompe (in caso di aggiornamento non interrotto).

+5

Questa risposta è inutile al 99% delle volte. Uno scenario _typical_ in cui _replacing_ una classe è inevitabile è quando il framework non è progettato per essere detto alla classe _which_ da utilizzare.Utilizza una classe denominata Library \ LibraryClass, full stop, e semplicemente _cannot_ deve essere configurata per utilizzare App \ MyClassDerivedFromLibraryClass. Il richiedente ha chiesto MOLTO in modo specifico come agganciare correttamente il caricamento automatico di Composer in modo che cerchi Library \ LibraryClass _first_ nella mia directory, _then_ nella directory della libreria. Trattaci un sermone sui principi OOP oltre a, invece di rispondere alla domanda. –

+0

Se il tuo framework non è progettato per cambiare le classi liberamente, allora forse dovresti considerare di usare un altro FW? Sono d'accordo sul fatto che, come ho detto, la mia risposta si adatta solo a un mondo perfetto. Si adatta perfettamente anche alla domanda OP perché l'OP può cambiare quale classe viene istanziata. Sentiti libero di fare un'altra domanda, più specifica, se questa non è adatta a te. – Atrakeur

+0

Non vedo nulla nella domanda OP che suggerisce all'OP di poter cambiare quale classe viene istanziata. Al contrario, il fatto che menzionino espressamente Composer accenna alla loro incapacità di farlo. Non conosco un modo per specificare con Composer quale classe deve essere istanziata. Questo è DI. Vedi la mia risposta qui sotto, da seguire a breve. –

2

C'è un'altra opzione. Nel caso abbiate bisogno di riscrivere l'unica classe è possibile utilizzare files in composer.json come questo

"autoload": { 
    "files": ["path/to/rewritten/Class.php"] 
    } 

Quindi, se si vuole riscrivere la classe Some\Namespace\MyClass messo in questo modo

#path/to/rewritten/Class.php 

namespace Some\Namespace; 

class MyClass { 
    #do whatever you want here 
} 

Su ogni richiesta compositore caricherà quel file in memoria, quindi quando si tratta di usare Some\Namespace\MyClass - verrà utilizzata l'implementazione da path/to/rewritten/Class.php.

+0

Ciò causerà un avvertimento 'Risoluzione di classe ambigua ', quando si utilizza' compositore dumpautoload -a' o '-o' e si utilizzerà il file originale anziché quello sovrascritto. La soluzione di Szczepan emette anche questo avviso, come indicato da Oleg sopra, ma risolverà l'uso della classe personalizzata anziché quella originale. – flu

Problemi correlati