PHP PSR-0 + diversi namespace in un unico file e caricamento automatico

2

Ho pensato per un po 'di tempo a definire diversi spazi dei nomi in un file php e quindi avere diverse classi all'interno di questo file.

Supponiamo che voglio implementare qualcosa come Doctrine\ORM\Query\Expr :

Expr.php
Expr
|-- Andx.php
|-- Base.php
|-- Comparison.php
|-- Composite.php
|-- From.php
|-- Func.php
|-- GroupBy.php
|-- Join.php
|-- Literal.php
|-- Math.php
|-- OrderBy.php
|-- Orx.php
'-- Select.php

Sarebbe bello se avessi tutto questo in un unico file - Expr.php :

namespace Doctrine\ORM\Query;
class Expr {
    // code
}

namespace Doctrine\ORM\Query\Expr;

class Func {
    // code
}

// etc...

Quello che sto pensando è la convenzione di denominazione delle directory e, a differenza di PSR-0 con diverse classi e spazi dei nomi in un unico file. È meglio spiegato dal codice:

ls Doctrine/orm/query
Expr.php

questo è - solo Expr.php

Poiché Expr.php è in qualche modo chiamato "meta-namespace" per Expr\Func , ha senso posizionare tutte le classi in Expr.php (come mostrato sopra).

Quindi, il nome del venditore inizia ancora con una lettera maiuscola ( Doctrine ) e le altre parti dello spazio dei nomi iniziano con lettere minuscole. Possiamo scrivere un autoload in modo da rispettare questa nozione:

function load_class($class) {
    if (class_exists($class)) {
        return true;
    }
    $tokenized_path = explode(array("_", "\"), DIRECTORY_SEPARATOR, $class);
    // array('Doctrine', 'orm', 'query', 'Expr', 'Func');
    //                                    ^^^^
    // first, we are looking for first uppercased namespace part
    // and if it's not last (not the class name), we use it as a filename 
    // and wiping away the rest to compose a path to a file we need to include
    if (FALSE !== ($meta_class_index = find_meta_class($tokenized_path))) {
        $new_tokenized_path = array_slice($tokenized_path, 0, $meta_class_index);
        $path_to_class = implode(DIRECTORY_SEPARATOR, $new_tokenized_path);
    }
    else { // no meta class found
        $path_to_class = implode(DIRECTORY_SEPARATOR, $tokenized_path);
    }
    if (file_exists($path_to_class.'.php')) {
        require_once $path_to_class.'.php';
    }
    return false;
}

Un altro motivo per farlo è ridurre un numero di file php sparsi tra le directory. Di solito controlli l'esistenza dei file prima di aver bisogno di un file per fallire con garbo:

file_exists($path_to_class.'.php');

Se dai un'occhiata a Doctrine\ORM\Query\Expr codice, vedrai che usano tutte le "inner-classes", quindi fai effettivamente:

file_exists("/path/to/Doctrine/ORM/Query/Expr.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/AndX.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Base.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Comparison.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Composite.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/From.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Func.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/GroupBy.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Join.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Literal.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Math.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/OrderBy.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Orx.php");
file_exists("/path/to/Doctrine/ORM/Query/Expr/Select.php");

nel tuo autoload che causa parecchie letture I / O. Non è troppo per controllare l'hit di ogni utente?

Sto solo mettendo questo in una discussione.

Voglio sentire da altri programmatori PHP cosa ne pensano. E, naturalmente, se hai una pallottola d'argento che affronta questi problemi che ho designato qui, per favore condividi.

Ho anche pensato se la mia domanda di moda si adattava qui e secondo the FAQ sembra che questa domanda sia indirizzata al software architettura "problema slash proposta.

Mi dispiace se il mio scarabocchio potrebbe sembrare un po 'goffo :) Grazie.

    
posta Nemoden 09.08.2012 - 04:23
fonte

3 risposte

5

Continua a utilizzare un singolo file per classe.

Usi APC, giusto? Se non lo fai, inizia a farlo adesso. APC memorizzerà l'opcode nella cache, quindi non ci sarà alcun riscontro di prestazioni sul controllo dei file.

Non vale la pena perdere così tanto leggibilità.

    
risposta data 17.10.2012 - 18:12
fonte
1

Non sono convinto che tu voglia veramente avere tutte le tue classi in un unico file. Certo che è possibile, ma non vorrei mantenerlo. Puoi utilizzare più spazi dei nomi in un unico file . Esistono due sintassi consentite:

Esempio n. 1 Dichiarazione di più spazi dei nomi, sintassi di combinazione semplice

<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
?>

Esempio n. 2 Dichiarazione di più spazi dei nomi, sintassi con parentesi

<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}

namespace AnotherProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}
?>

Vorrei andare con il secondo, per motivi di leggibilità, manutenzione ed eliminazione degli errori.

Tuttavia, non mi piace l'idea di utilizzare un file per più classi . Vorrei suggerire di utilizzare un file per classe, organizzato in cartelle in base al tuo spazio dei nomi. Ciò ti consente di utilizzare un autoloading davvero semplice:

spl_autoload_register(function ($className) {
    $className = (string) str_replace('\', DIRECTORY_SEPARATOR, $className);
    if(file_exists($className)) {
        include_once($className . '.class.php');
    } else {
        // throw class not found
    }
}); 

Questo è uno schema che di solito uso nelle mie applicazioni. Se sei preoccupato dell'IO e della velocità, guarderei le cose di cui parlava Yannis Rizos:

Have you thought of just putting everything in a phar archive? Still a file per class (easier to maintain), but a bit less strain on the filesystem (especially with APC).

Potresti anche utilizzare il compiler HipHop .

    
risposta data 03.10.2012 - 13:44
fonte
0

Stavi chiedendo se le classi in questione avrebbero causato un IO in ogni classe. Ma potresti aver trascurato questo codice all'inizio della funzione di caricamento automatico

if (class_exists($class)) {
    return true;
}

non appena viene caricato il file 'contenitore' Expr.php, tutte le classi interne verranno registrate in php e quindi ogni successiva chiamata al caricamento automatico risulterebbe in class_exists() == true

Se decidi di avere diverse classi in un file, assicurati semplicemente che la classe che risolve correttamente il caricamento automatico venga utilizzata prima di qualsiasi altra classe inline. Ciò farebbe effettivamente risparmiare I / O rispetto all'approccio one-class-per-file.

    
risposta data 17.10.2012 - 18:05
fonte

Leggi altre domande sui tag