Mi trovo in questo momento a sbattere la testa con il seguente problema (in PHP):
Ho una classe base astratta, che ha un metodo non astratto, ereditata e invariata su tutta la catena ereditaria (che è a 3 livelli in questo momento, solo il primo livello è astratto).
Questo metodo non astratto contiene la logica per calcolare un percorso del disco, che viene eseguito prendendo in considerazione il nome della classe. Sia i bambini che i nipoti adottano questo metodo / algoritmo senza modifiche.
Tuttavia, desidero implementare la funzionalità in modo che se un Nipote non ha il proprio percorso specifico sul disco, tenterà di utilizzare il percorso del suo genitore. Solo il genitore può calcolare questo percorso (solo il genitore conosce il proprio nome) - Non voglio usare il reflection per memorizzare il nome del genitore in una variabile, e mi piacerebbe anche che funzioni in modo omogeneo - se la catena di ereditarietà è più lunga , dovrebbe cercare di risalire la catena ereditaria per chiedere a qualcuno dei suoi antenati un "luogo" (il percorso sopra indicato).
Una chiamata di parent::Method()
in PHP (come in altri linguaggi OOP) proverà a chiamare il genitore della classe corrente , non il genitore della classe dell'oggetto in fase di esecuzione.
In PHP, si può farlo attraverso Reflection, ma sono più o meno persuaso che ciò infrange alcuni principi dell'OOP di cui non sono a conoscenza.
//Abstract class BaseSomething...
if(!$this->Calculation()) {
$parentClass = (new \ReflectionObject($this))->getParentClass();
if(!$parentClass->isAbstract()) {
$method = $parentClass->getMethod('Calculation');
$method->setAccessible(true);
$this->result= $method->invoke($this, $arg ...);
}
}
Funziona, fa il lavoro. Permette una pseudo-ricorsione di sorta, fermandosi al primo antenato che può fornirci ciò di cui abbiamo bisogno, ma qualcosa deve essere più o meno sbagliato lungo la strada.
Una possibile soluzione per cui penso stia avendo una catena di costruttori, in cui ogni classe aggiunge il suo nome a una matrice. Ciò implicherebbe forzare ogni bambino a chiamare il costruttore del genitore e anche ad aggiungere il suo nome alla matrice, che non è neanche carina.
Forse il problema risiede in ciò che sto cercando di fare - usare l'ereditarietà in un modo più comprensivo di quello che è stato inteso fare.
Mi piacerebbe sentire alcune riflessioni su come questo possa essere rifattorizzato in modo tale da non infrangere le regole, o forse qualcuno potrebbe prendere in considerazione il mio caso d'uso, usando questo codice di ridefinizione delle basi è "ammissibile".
Modifica: mi scuso per aver lasciato che questa domanda si allontanasse per più di un mese e sottrassi la mia responsabilità di aggiungere esempi e rispondere alle domande. Era, in parte, solo una pigrizia di base.
Proseguendo nella stessa vena del post originale, questo è il modo in cui i tre livelli sembrano approssimativamente (semplificati il più possibile, quasi identici a quelli precedenti):
abstract class BaseWidget extends \Illuminate\Routing\Controller {
private function getPath($file) {
$name = return get_called_class(); //Uses get_class_name
$file = $some_base_path . '/' . $name . '/';
if(file_exists($file)) {
return $file;
} else {
$refl = new \ReflectionObject($this);
$parentRefl = $refl->getParentClass();
$methodRefl = $parentRefl->getMethod('getPath');
$methodRefl->setAccessible(true);
$path = $methodRefl->invoke($this);
return $path;
}
}
}
class Widget extends BaseWidget {
//This guy resides in App/Widgets/Widget/Widget.php,
//and has a view in Widget/Views/View.blade.php
//When $widget->getPath('Views/View.blade.php') is called,
//it will know how to 'find itself' and where to look for its own
//view
}
class SpecialisedWidget extends Widget {
//This guy resides in ...Widgets\SpecialisedWidget.php
//Its 'views' folder is empty, so when it has to find it,
//it will instead borrow it from its parent. If this class
//also had a child with no view, it would go up to Widget on the
//inheritance chain.
}
Riconosco che sto usando l'ereditarietà per fare qualcosa che l'ereditarietà non dovrebbe fare. Tuttavia, la funzionalità che ho dovuto implementare - Un Widget che prende in prestito le viste dal suo genitore, che sono relative alla posizione del genitore sul disco - di cui il bambino non è a conoscenza - ha reso necessario cheat un po '.