overloading costruttore

Solitamente utilizzo questa implementazione del costruttore:

  public function __construct() {
    $num_args = func_num_args();
    $args = func_get_args();
    call_user_func_array(array(&$this, '__construct_'. $num_args), $args);
  }

e a seguire una serie di implementazioni di funzioni che farebbero da costruttori overloadingati (scusate la forzatura):

  public function __construct0() {}
  public function __construct1($par) {}
  public function __construct2($par1, $par2) {}
  public function __construct3($par1, $par2, $par3) {}

L'idea potrebbe essere buona, ma ho un problema che l'overloading in altri contesti è risolto. Il sistema che uso fa conto solamente del numero dei parametri, e della tipologia.

Se io avessi due costruttori che prenderebbero ad esempio una coppia di parametri attuali per costruttore, i cui tipi sono diversi, data la natura di PHP che di questo sistema, mi ritroverei due funzioni il cui nome è uguale (__construct2) e non distingue quale costruttore chiamare, a parte il messaggio di errore circa la definizione di due metodi di egual nome.

Da quì la prima soluzione che vorrei sottoporvi, sempre nell'esempio di due costruttori con due parametri di tipologia diversa:

  public function __construct() {
    $num_args = func_num_args();
    $args = func_get_args();
    if ($num_args == 2) {
        $costructor_name = "_";
        if (is_string($args[0])) {
            $costructor_name .= "string"
        } elseif (is _int($args[0])) {
            $costructor_name .= "int";
        }
        $costructor_name .= "_int";
    }
    call_user_func_array(array(&$this, '__construct_'. $num_args. $costructor_name), $args);
  }
  public function __construct2_string_int($p1, $p2) {
  }
  public function __construct2_int_int($p1, $p2) {
  }

La seconda soluzione potrebbe essere la seguente:

  public function __construct() {
    $num_args = func_num_args();
    $args = func_get_args();
    call_user_func_array(array(&$this, '__construct_'. $num_args), $args);
  }
  public function __construct2($p1, $p2) {
    if (is_int($p1)) {
        $this->par_int = $p1;
    } elseif (is_string($p1)) {
        $this->par_string = $p2;
    }
    $this->par_generic = $p2;
  }

La seconda soluzione potrebbe generare qualche problema di nomi dei parametri, perché potrei passare un int o una stringa da valorizzare presso diversi attributi dell'oggetto, e nomi non esatti o troppo generici potrebbero confondere chi poi andrà ad utilizzare questa classe.

Teoricamente avrei risolto, ma vorrei pareri in merito e se esistono altre soluzioni ben migliori di queste.

Avevo in mente altre possibili soluzioni ma, passate ad uno studio approfondito avevano forti problemi e le ho scartate.

Tuttavia temo che un costruttore del genere possa via via crescere sempre più e sporcare così la definizione della stessa classe, e la necessità di demandare ad una funzione o ad un costruttore astratto, così da non dover ricopiare n volte lo stesso frammento per n classi...

Ma non mi son spinto fino a qui, per ora.

Pareri, grazie.

inviato 6 anni fa
larchitetto
X 0 X

Non capisco perchè crei più costruttori.

Io userei un oggetto un costruttore, non un oggetto più costruttori...

Cioè creerei un'unica funzione per la costruzione dell'oggetto, a seconda dei parametri che passo si comporta nei modi che decido io...

Un unico costruttore del tipo:

  public function __construct($par1=NULL, $par2=NULL, $par3=NULL) {}

Oppure il numero delle variabili non è costante e possono aumentare?

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Creo diversi costruttori un po' per... chiamiamola abitudine xD

Solitamente il numero di attributi è ben definito, però in base alla situazione potrei valorizzarne alcuni e non altri.

Non mi è capitato finora che il numero delle variabili vari...

risposto 6 anni fa
larchitetto
X 0 X

Ripeto, io userei un unico costruttore, poi a seconda di che variabili vengono passate mi comporto in un modo o in un altro.

ciao

risposto 6 anni fa
Mario Santagiuliana
X 0 X

ok, inteso.

forse una domanda stupida, ma in presenza di un certo numero di classi forse potrebbe non esserlo più.

una classe con diversi costruttori così come l'ho proposta io, potrebbe incidere sulle prestazioni?

 :bye:

risposto 6 anni fa
larchitetto
X 0 X

Non di molto immagino.

Però non usi più la logica degli oggetti a php che intende una funzione di costruzione denominata __constructor().

Se hai un oggetto che varia, cioè non è più un oggetto "stabile" non ti conviene creare un oggetto padre e più oggetti figli?

risposto 6 anni fa
Mario Santagiuliana
X 0 X

Si, mi converrebbe, ma ad esempio un esempio seguente, come lo risolveresti?

Stavo proprio per applicare il tuo suggerimento su questa classe, e mi son fermato. Posto solamente la parte dei costruttori, inizialmente è così:

 public function __construct() {
    $num_args = func_num_args();
    $args = func_get_args();
    call_user_func_array(array(&$this, '__construct_'. $num_args), $args);
  }
  public function __construct_0() {}
  public function __construct_1($item) {
    $this->link_path = $item['link_path'];
    $this->link_title = $item['title'];
    $this->options['attributes']['title'] = $item['description'];
  }
  public function __construct_2($link_path, $link_title) {
    $this->link_path = $link_path;
    $this->link_title = $link_title;
  }

Si potrebbe aggirare, indi è solo una curiosità...

risposto 6 anni fa
larchitetto
modificato 6 anni fa
X 0 X

Un unico costruttore mi sembra la scelta migliore, anche per la creazione successiva o futura di oggetti derivati.

public function __construct($item=NULL, $link_path=NULL, $link_title=NULL) {
    if($item && !$link_path) {
        $this->link_path = $item['link_path'];
        $this->link_title = $item['title'];
        $this->options['attributes']['title'] = $item['description'];
    } elseif($link_path && $link_title) {
        $this->link_path = $link_path;
        $this->link_title = $link_title;
    } else {
        $num_args = func_num_args();
        $args = func_get_args();
         call_user_func_array(array(&$this, '__construct_'. $num_args), $args);
    }
  }

Quando crei il tuo oggetto non devi stare li a "scervellarti" e ricordare quale dei tanti costruttori richiamare per inizializzarlo, basta solo ti ricordi l'interfaccia di chiamata e quale variabili passare.

risposto 6 anni fa
Mario Santagiuliana
modificato 6 anni fa
X 0 X

mmm mi piace  :coolsmiley:

risposto 6 anni fa
larchitetto
X 0 X
Effettua l'accesso o registrati per rispondere a questa domanda