2011-12-31 7 views
7

Gestisco un sito di giochi arcade e negli ultimi anni ha aggiunto molte funzionalità, è arrivato al punto in cui la programmazione procedurale sembra troppo complicata e aggiunge nuove funzionalità o semplifica le modifiche al design possono essere molto complicate.Scelta delle classi da utilizzare in un progetto di php OOP

Pertanto, ho deciso di provare a ricodificare il sito da zero con le stesse funzionalità, ma in un formato OOP.

Il problema che ho è scegliere le classi, capisco OOP e come dovrebbe funzionare, ma sembra sempre avere problemi per iniziare. Non sono sicuro se dovrei provare a creare funzioni per classi come una classe utente con la funzione utente di accesso o se la classe utente dovrebbe essere solo aggiungere/aggiornare/mostrare i dettagli utente e la parte di accesso sarebbe meglio in un sistema classe?

Al momento ho iniziato con la classe e le funzioni seguenti, ma rientrano in questa categoria?

<? 
class User { 

    var $userId, 
     $username, 
     $userRole, 
     $userEmail; 

    function isLoggedIn(){ 

    } 

    function login($postusername, $postpassword) 
    { 

    } 

    function increaseLoginCount(){ 

    } 

    function logout(){ 

    } 
} 
?> 

ho potuto quindi avere qualcosa di simile a quanto segue in un page.php .. (collegare classe non mostrato)

<? 
$db = new Connect; 
$db->connect(); 

$user = new User; 

if(!$user->isLoggedIn()) 
{ 
    echo "Please Log In."; 

    if($_POST['user']) 
    { 
     $user->login($_POST['username'], $_POST['password']); 
    } 
} 
else 
{ 
    if($_POST['logout']) 
    { 
     $user->logout(); 
     exit; 
    } 

    echo $user->username." Logged In.<br />"; 
} 
?> 

Ma poi il sito sarebbe avere pagine per mostrare le categorie di gioco e I don' so dove si adatta la funzione displayGames() in quanto non è un singolo gioco, quindi non andrebbe nella classe 'Game'?

ho cercato di trovare esempi 'mondo reale' ma il codice php mi mostra come fare un cambiamento di colore elefante o la danza non aiuta ...

+0

ho le funzioni codificate ma semplificare questo esempio sono stati rimossi. – Dan

risposta

9

Cominciamo con un po 'di analisi testuale, mette in evidenza da me:

corro un sito Arcade e sopra le ultimi anni

pensare a quanto si sono in grado di affrontare e con cosa si sta trattando.Comprendi anche che nel corso degli anni hai acquisito la conoscenza specifica su sito arcade in esecuzione. Hai guadagnato la professione nella tua zona. Non sottovalutare mai la tua posizione e le tue risorse, è la base da cui stai operando e introdurrai cambiamenti. Questo include la base utente del tuo sito.

Ha avuto molte caratteristiche aggiunto, è ottenuto al punto in cui la programmazione procedurale sembra proprio troppo complicato e l'aggiunta di nuove funzioni o fare semplici modifiche di progettazione possono essere molto difficile.

Se i sistemi crescono, diventano sempre più complicati. Quello è non specifico per la programmazione procedurale solo, è un dato di fatto. Poiché gestisci il sito da molti anni, sai come sono cambiate le cose, specialmente nell'area in cui l'utente si interfaccia con il tuo sito.

Perciò ho deciso di provare e ricodificare il sito da zero con le stesse caratteristiche ma in un formato OOP.

Si dice che potrebbe essere possibile utilizzare le tecniche OOP per rendere il software riutilizzabile, non c'è (e non può essere) alcuna prova di ciò.

Ma ci sono solo pochissimi esempi nello sviluppo di software commerciale in cui la riscrittura dell'intera applicazione da zero è stata un successo. Molto pochi. Le regole dello sviluppo del software commerciale potrebbero non essere applicabili nel tuo caso specifico, quindi basta dire.

Pensaci due volte prima di ricodificare il sito. Fare un sacco di lavoro solo per raggiungere lo stesso è in qualche modo infruttuoso e può essere deludente. Probabilmente invece guardi in modo più specifico quale del tuo attuale design sta introducendo il problema più grande che vorresti cambiare.

E 'possibile con PHP per mescolare procedurali e object-oriented stile, che può essere particolarmente utile quando si hanno (codice di una definizione comune di codice legacy è w/o test automatizzati) codice legacy.

Il problema che ho è in ripresa le classi,

provo a riformulare che: Per quale scrivere le classi per?

ho capito OOP e come dovrebbe funzionare, ma sembrano sempre avere problemi di iniziare.

L'inizio è sempre il passo più difficile. Sei nella posizione pronta a prendere decisioni ora, ma non puoi guardare al futuro. Ridurre il rischio eliminando la parte più rischiosa. Probabilmente hai iniziato a fare una domanda qui per ottenere un feedback su cui basare le tue decisioni, ma questo probabilmente non ridurrà l'onere e potrebbe portare a confusione.Tuttavia, essere istruiti è spesso una buona cosa.

non sono sicuro se devo essere cercando di fare le funzioni per le classi come ad esempio una classe utente con accesso a funzioni utente o se la classe utente dovrebbe essere solo per aggiungere/aggiornamento/mostra dettagli utente e il log in parte sarebbe meglio in una classe di sistema?

Ciò dipende in gran parte dalla natura dell'applicazione e dalla natura dell'utente. Probabilmente la maggior parte del tuo script ha solo bisogno di sapere se un utente è concreto o anonimo (un utente anonimo non ha effettuato il login), è ID, nome o nickname.

L'applicazione deve fornire tale utente a qualsiasi componente che consuma, quindi ogni comando/script non deve occuparsi di a) ottenere informazioni e gestire gli utenti (come l'accesso), b) verificare se il componente è valido per l'utente utente (controllo di accesso). Questo dovrebbe essere collocato altrove, ad es. nello application controller­PofEAA.

Ciascuno degli script/comandi con l'oggetto controller dell'applicazione può chiedere all'utente e interagire con l'utente.

Tuttavia, questo è solo tecnicamente parlando. Affronta il fatto che tu stesso non sei sicuro, lavora con quella informazione. Cerca di formulare meglio il tuo problema concreto, elencare vantaggi e svantaggi per un modo specifico di risolverlo, allontanati di nuovo dal codice concreto prima di iniziare a codificare. Quindi confrontare i pro ei contro. Cerca di rendere le cose più semplici e meno complicate.

Probabilmente scrivere in parole semplici cosa dovrebbe accadere invece di scrivere codice.

Al momento ho iniziato con la classe seguente e funzioni ma si inseriscono in questa categoria **? **

Il codice è abbastanza spoglia, quindi è difficile per dire molto - specialmente perché non so qual è il tuo sito arcade (e di che categoria si scrive). È ancora buono per un esempio, probabilmente. Ciò che può essere visto nei tuoi corsi è che tu integri strettamente tutto l'uno con l'altro.

Ad esempio, si inizia con il DB. Questo è comune, perché il DB è un componente centrale per qualsiasi applicazione. L'applicazione richiede il funzionamento del DB. Tuttavia, si desidera mantenere le cose liberamente accoppiate in modo che tutti i comandi possano essere eseguiti con un altro DB o un nuovo oggetto utente collegato a qualche altro DB rispetto al resto degli oggetti dati dell'applicazione.

$application->getDB(); 

Poiché l'utente è un argomento così centrale in ciascuna applicazione, dovrebbe avere un'interfaccia molto semplice. Tutti i dettagli di gloria sull'autenticazione, recupero delle proprietà degli utenti, ecc dovrebbero essere delegate in un'altra classe/componente, in modo da poter modificare l'implementazione in cui sono memorizzati gli utenti e come si autenticano:

/** 
    * @package command.modules.games 
    */ 
function ListGamesCommand(Request $request, Response $response) 
{ 
    $application = $request->getApplication(); 
    $user = $application->getSession()->getUser(); 
    $games = $application->getModels()->build('games'); 
    $games = $games->findByUser($user); 
    $response->setProp('games', $games); 
} 

come mostra questo esempio , puoi aggiungere la funzionalità quando ne hai bisogno. Per esempio. finché l'applicazione non ha bisogno di accedere effettivamente agli utenti, perché preoccuparsi di come è scritta ora?

Creare una fabbrica che sta producendo l'utente per l'oggetto applicazione - qualunque cosa avrà bisogno ora o in futuro (vedere le due pile di oggetti in The Clean Code Talks — Inheritance, Polymorphism, & Testing). Se è quindi necessaria l'autenticazione, aggiungerla all'oggetto di sessione o all'interfaccia dell'oggetto utente.

L'autenticazione stessa sarebbe comunque implementata in una classe a sé stante, il Authenticator. Quindi puoi rivedere le tue interfacce anche in seguito, spostando l'invocazione dell'autenticazione dalla sessione all'utente o da qualsiasi altra cosa. Solo una minima parte dei tuoi comandi dovrà occuparsi di questi compiti specifici e poiché tutto il nuovo codice è sottoposto a test automatici, poiché desideri riscrivere e trarre vantaggio da OOP, hai assicurato che tutti i luoghi siano coperti e adeguatamente riprogettati.

Lo stesso vale per l'accesso alle variabili di richiesta. Se vuoi sfruttare i vantaggi di OOP - che è altamente connesso con l'indirezione (e ogni livello di riferimento indiretto ha un prezzo) - devi prima di tutto operare le tue classi base su dati specifici e non su dati (come globals e superglobals, ho visto $_POST nel tuo codice di esempio).

Quindi attivare il nuovo codice di operare su una richiesta e offrire una risposta (ingresso - Processing - Output):

$request = new Request($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV); 
$response = new Response; 

esempio tratto dal BankAccount - Sample application used for PHPUnit training

Ora tutto sotto di questo può funzionare su un Request e un oggetto Response - input di processo e trasformarlo in uscita. Il comando di dominio (i tuoi script/comandi che eseguono la cosa) non devono più preoccuparsi di estrarre l'input dalla richiesta HTTP come utilizzando $_POST o $_GET possono prenderlo direttamente dallo Request - o se scrivi una classe di comandi propri - questo può essere ancora più personalizzato. E alcuni comandi possono operare su richieste e risposte proprie.

Il prossimo grande argomento è l'interfaccia utente. Si scrive che si desidera:

ho deciso di provare a ricodificare il sito da zero con le stesse caratteristiche, ma in un formato OOP.

Ho già scritto che una tale azione può essere infruttuosa. Avere un vantaggio del codice OOP significherebbe che la prossima volta che si cambia il codice, si è ancora in grado di riutilizzare i componenti. Poiché il software cambia costantemente, questa volta è già la prossima volta. Quindi vuoi riutilizzare già il codice esistente. Presumo che una parte del codice esistente sia la logica di output. Quindi la logica di uscita esistente deve interfacciarsi con l'esemplare Request e Response precedente.

Scommetto che ami i siti web. Ti piace farli funzionare e sembrano grandi. Hai costruito il tuo sito nel corso degli anni e anche se non tutto è come vorresti che fosse, non vuoi lasciarlo cadere. Quindi è fondamentale per la tua riscrittura che non distruggi tutto ma puoi preservare la sua forma di lavoro da ora al futuro (Vedi anche Preserve a Working Application; last point of the list).

In webapps la vista è una parte così cruciale. Se perdi la vista, il tuo sito perderà la sua identità.Se ne modifichi troppo, il tuo sito perderà gli utenti che sono a loro agio nell'usarlo oggi.

Se lo rompi,

  1. vi accorgono neppure?
  2. puoi aggiustarlo?

D'altra parte si desidera il codice dell'applicazione (le caratteristiche, le funzionalità) per non essere così strettamente legata ad essa più per avere un beneficio nel riscrivere il codice. Come si vuole riscrivere la vostra applicazione, diamo uno sguardo:

 .---------.       .-------------. 
    | website | ---> [interface in ] ---> | application | 
    | user | <--- [interface out] <--- |    | 
    `---------´       `-------------´ 

Come questo schema mostra, per rendere l'applicazione più indipendente a tutto ciò che l'interazione si presenta come (può essere un sito web, una GUI (smartphone) o sistema di ticketing), il codice dell'applicazione dovrebbe essere sostituibile. Non si desidera codificare la logica per ottenere giochi per gli utenti, ad esempio per ogni tipo di interfaccia utente nel nuovo codice dell'applicazione, ma si è fatto nel vecchio codice dell'applicazione.

Prendendo come esempio l'oggetto User. Il modo in cui si autentica e dove viene memorizzato non dovrebbe essere qualcosa a cui il nuovo codice dei comandi dell'applicazione è preoccupato. È lì solo se il comando ne ha bisogno. Non globalmente ma specificamente se il comando lo richiede.

Dove-come le procedure di registrazione e password perse fanno parte dell'applicazione esistente e continuano ad esistere.

Ora è necessario riunire il vecchio e il nuovo codice.

Quindi probabilmente inizierai con un'interfaccia per le richieste HTTP e una risposta HTTP. La visualizzazione inizia con Interface Out. Assegni/passi tutti i dati necessari per la vista tramite tale interfaccia, la tua applicazione non conosce la vista più a lungo. Non ti occupi di alcun codice CSS, Javascript o HTML all'interno del tuo nuovo codice applicazione. Questo è solo lo zucchero in cima per l'output. La tua applicazione dovrebbe interfacciarsi anche tramite console/telnet in formato testo o come servizio XMLRPC remoto, endpoint AJAX - qualunque cosa.

Quindi è possibile semplicemente generalizzare il proprio codice di vista e inserire variabili in esso. Scrivere un livello di visualizzazione potrebbe essere semplice come includere un file PHP. Funziona su variabili disponibili all'interno del suo ambito. Può utilizzare le funzioni "helper" (macro modello) disponibili nel suo ambito. Può utilizzare visualizzare gli oggetti del modello. È anche possibile scrivere la propria lingua per la visualizzazione (lingua dei modelli, una lingua di dominio specifica (DSL)).

Ma ciò è possibile solo se si crea un'interfaccia che consenta al codice dell'applicazione di farlo.

Quindi quello che fai ora è spostare via HTTP/HTML/CSS/JS dalla tua applicazione in un adattatore di sua proprietà. Tale adattatore è in grado di formulare il comando generico che può essere passato a qualsiasi applicazione tramite l'interfaccia in.

L'applicazione si occuperà solo di eseguire il comando e consegnare la risposta tramite interfaccia. Quindi hai ora due domini: la tua applicazione e il sito web.

È possibile iniziare a creare questi due nuovi domini e quindi offrire un'interfaccia in entrata e in uscita per il codice legacy e uno per il nuovo codice.

Si dispone anche di "due" applicazioni una accanto all'altra. Finalmente sono legati insieme (invisibili nel loro codice) con il tuo database che si occupa di tenere in ordine i dati del tuo sito. E questo è ciò che il database è per. Separa i dati dal tuo codice, così puoi cambiare il tuo codice nel tempo.

Inoltre, se si desidera ricodificare, tracciare un bordo tra il codice esistente e il nuovo codice.

Buona fortuna! E spero di leggere questo ti mostrerà alcune opzioni per il tuo caso specifico. Si noti inoltre che non si trasformano i controller in un'altra facciata del database. Probabilmente hai i migliori benefici (non conosci il tuo più grande problema concreto) utilizzando una leggera astrazione HTTP e un livello di visualizzazione solo come potrebbe essere che la tua applicazione sia solo per i siti web.

Perché, come in HTTP/PHP:

[Interface In] Plain Text HTTP request 
[Application] Free to go 
[Interface Out] Plain Text HTTP response 

di solito usati solo alcune funzionalità per analizzare l'input e l'output costruire.

Inoltre, l'assenza di modelli di grasso ha il vantaggio di accedere ai dati rapidamente e in modo sequenziale, ad es. se non è necessario passare l'output in una sola volta (bufferizzato, un blocco), è possibile trarre vantaggio dal flusso dell'output sul server.

È necessario decidere quali parti sono importanti per il refactoring per la propria applicazione, non per OOP o meno. Come procedurale, anche l'OOP deve essere fatto bene. Se oggi ti imbatti in problemi scrivendo codice procedurale, il codice OOP potrebbe non essere la risposta al tuo problema. Potrebbe essere necessario scrivere un codice procedurale migliore. Solo dicendo, non è facile refactoring di un'applicazione e si dovrebbe identificare il problema reale prima.

  1. Se lo rompi, te ne accorgi?
  2. Se lo rompi, puoi aggiustarlo?

La parte cruciale è che puoi notare e che hai tutto a portata di mano per fare la correzione.

Ottieni il tuo sito Web sotto test, in modo che tu possa dire se cambiare codice qui o là sta effettivamente facendo del bene. Essere in grado di trasformare qualsiasi cambiamento in caso di luce non funziona (meglio).

Ciò consente di decidere facilmente una nuova funzione o meno. Finché non è necessario introdurre nuove funzionalità, non è necessario modificare nulla nella modalità di scrittura delle funzioni. E fino a lì, non puoi pianificare le nuove funzionalità.

Quindi meglio pensarci due volte prima di riscrivere l'applicazione. Come scritto, questo può uccidere il progetto.


Vedere anche:How to implement MVC style on my PHP/SQL/HTML/CSS code?­SO Q&A

0

Tutti i membri nello sguardo classe utente come loro appartengono a questo. È importante separare il codice GUI da un altro codice, metterei displayGames() in una sorta di classe gui.

7

OOP si occupa di identificare le aree di responsabilità e di costruire unità di codice autonome destinate a gestire una, e una sola, di quelle aree. Una regola empirica generale è che ogni oggetto nel tuo sistema dovrebbe incarnare un oggetto o un concetto equivalente nel mondo reale, ma ciò non è sempre vero in quanto devi anche preoccuparti delle cose astratte che sono necessarie per far funzionare il tuo sistema (voglio dire astratto qui nel senso che non rappresentano un elemento della logica aziendale, ma sono comunque necessari per far funzionare il sistema. Non intendo le classi astratte, che è tutt'altra cosa).

Ad esempio, nel tuo sito di giochi, probabilmente dovrai occuparti di giochi, utenti, moderatori, account, recensioni, commenti e così via. Ognuno di questi dovrebbe essere una classe a sé stante, e ogni istanza di quella classe dovrebbe rappresentare un particolare utente, gioco, commento e così via.

Ma le classi hanno aree di responsabilità e, come affermato sopra, una classe dovrebbe occuparsi della sua area di responsabilità e nient'altro. Il rendering di una pagina non è responsabilità di nessuna delle classi di oggetti menzionate sopra. Qui è dove entrano le classi che non rappresentano le entità del tuo sistema. Probabilmente avrai bisogno di una classe per una Page, una classe per una sessione, una classe per le connessioni al database (sebbene PHP ti abbia già parlato con PDO e alcuni degli altri moduli DB come mysqli).

Per eseguire il rendering di una pagina si utilizzerà un'istanza di una classe di pagina. Passeresti un riferimento all'oggetto utente registrato, i riferimenti a qualsiasi oggetto di gioco che desideri venga visualizzato e così via. Quindi dovresti renderizzare l'HTML vero. La classe Page non ha bisogno di sapere nulla del funzionamento interno degli oggetti che si passano, a parte le API che questi oggetti espongono (note in cerchi OOP come il protocollo dell'oggetto, in altri i loro metodi e proprietà pubbliche).A (molto di base) di classe pagina potrebbe essere simile a questo:

class Page 
{ 
    private $user = NULL; 
    private $games = array(); 

    public function setUser (User $user) 
    { 
     $this -> user = $user; 
    } 

    public function getUser() 
    { 
     return ($this -> user); 
    } 

    public function addGame (Game $game) 
    { 
     $this -> games [] = $game; 
    } 

    public function getGames() 
    { 
     return ($this -> games); 
    } 

    public function generate() 
    { 
     $user = $this -> getUser(); 
     $games = $this -> getGames(); 

     $pageFile = '/path/to/a/php/script/representing/the/page/markup.php'; 
     require ($pageFile); 
    } 

    public function __construct (User $user, array $games) 
    { 
     $this -> setUser ($user); 
     foreach ($games as $game) 
     { 
      $this -> addGame ($game); 
     } 
    } 
} 

Lo script markup.php attuale sarebbe probabilmente simile a questa:

<html> 
    <head> 
     <title>Games page for <?php echo ($this -> user -> getName()); ?> 
    </head> 
    <body> 
    <p>Hello, <?php echo ($this -> user -> getName()), here are your games.</p> 
    <?php if (count ($this -> games)) { ?> 
    <ul> 
     <?php foreach ($this -> games as $game) { ?> 
     <li><?php echo ($game -> getName()); ?>: your best score is <?php echo ($game -> getHighScore ($this -> user)); ?></li> 
     <?php } ?> 
    </ul> 
    <?php } ?> 
    </body> 
</html> 

Come forse avrete notato, se si utilizza questo approccio allora i moduli della tua applicazione tenderanno a cadere in una delle tre categorie. I tuoi oggetti logici di business come Utente e Gioco, la tua logica di visualizzazione come il file markup.php e il terzo gruppo che serve come una forma di logica e coordinamento della colla come la classe Page.

Mentre in questo caso particolare è specifico per il vostro sito, se si dovesse generalizzare ulteriormente questo approccio sarebbe cadere in un modello di progettazione conosciuto come MVC, che sta per Model, View, Controller (beh in realtà è più vicino a un modello chiamato PAC per Presentation, Abstraction, Controller, ma è quasi sempre chiamato MVC nella comunità PHP per qualche ragione, quindi diremo semplicemente MVC per ora). Un modello è una generalizzazione di una classe di problemi che i programmatori si imbattono in una base abbastanza regolare da avere a portata di mano un toolkit di soluzioni predefinite.

Nel caso dell'applicazione di gioco, Utente e Gioco sono modelli, Pagina è un controller e markup.php è una vista. Se sostituisci uno script markup.php diverso in questo codice, puoi usarlo per presentare esattamente gli stessi dati in un modo completamente diverso, ad esempio come un file XML. Puoi anche usare gli stessi modelli con un controller diverso per farli fare cose diverse. La cosa importante da tenere presente qui è che i modelli non devono preoccuparsi di come vengono utilizzati, in questo modo possono essere utilizzati in modi diversi a seconda di ciò che il controller deve ottenere.

Poiché MVC è uno schema, esistono già toolkit per la creazione di applicazioni MVC (benché non siano realmente MVC;)) in PHP. Questi sono chiamati framework. Ci sono molte opzioni tra cui scegliere, come Symfony, CodeIgnitor, Zend Framework e così via. La struttura più popolare in questi giorni è Zend, anche se non ne sono personalmente un fan. (Direi che le versioni beta di Zend Framework 2 sono comunque molto migliori rispetto alla versione attuale del framework).

Spero che questo sia stato utile per voi. So che l'OOP può essere scoraggiante all'inizio. Ti richiede di cambiare il tuo modo di pensare come programmatore, ma non ti preoccupare, arriverà con abbastanza pratica.

+1

+1 Ottimo commento su MVC in PHP. Mi infastidisce sempre che ora è diventato il termine comune in cui non si adatta perfettamente al paradigma PHP (certamente non in un ambiente basato sulle richieste). Vorrei sapere se Zend è il framework più popolare: http://www.google.co.uk/trends?q = zend + framework% 2Csymfony – liquorvicar

+0

Stavo basando quel commento sulla popolarità della mia recente esperienza nella caccia di un lavoro migliore. Tutti sembravano volere l'esperienza di Zend. :) – GordonM

+0

Abbastanza giusto. Dubito che qualcuno possa effettivamente dire con sicurezza che è sicuramente il framework PHP più popolare. Da dove mi siedo Symfony2 sembra essere "l'unico", ma poi ammetto che non mi sono mai dedicato a ZF2. – liquorvicar

0

Il post di GordonM è buono per iniziare. Consiglierei sicuramente di utilizzare una struttura consolidata per iniziare: fanno molto per te e ti aiuteranno ad abituarti a OOP in PHP. Personalmente, se stai usando PHP5.3, ti consiglio Symfomy2 ma è puramente una preferenza personale. Quello che vorrei anche suggerire è ottenere una copia di the "Gang of Four" book. È una lettura pressoché essenziale e, sebbene provenga principalmente da uno sfondo non basato sulla richiesta, molti dei pattern sono ancora rilevanti in PHP.

Problemi correlati