Wanneer statische gebruiken vs geconcretiseerd klassen

PHP is mijn eerste programmeertaal. Ik kan niet helemaal wikkel mijn hoofd rond wanneer statische klassen vs instantievorming voorwerpen.

Ik realiseer me dat je kunt dupliceren en kloon objecten. Maar in al mijn tijd met behulp van php elk object of de functie altijd eindigde als een enkele return (array, koord, int) waarde of ongeldig.

Ik heb begrepen concepten in de boeken als een video game personage klasse. duplicate auto object en maken de nieuwe rood , dat klopt allemaal, maar wat niet is de toepassing ervan in php en web apps.

Een eenvoudig voorbeeld. Een blog. Wat voorwerpen van een blog best zou worden uitgevoerd als statische of een instantie objecten? De klasse DB? Waarom niet gewoon een instantie van de db object in het globale bereik? Waarom niet in plaats daarvan maken elk voorwerp statische? Hoe zit het met de prestaties?

Is het allemaal gewoon stijl? Is er een juiste manier om dit soort dingen te doen?


Antwoord 1, Autoriteit 100%

Dit is een interessante vraag – en antwoorden zou kunnen krijgen interessant ook ^^

De eenvoudigste manier om dingen te overwegen zou kunnen zijn:

  • Gebruik een instanciated klasse waarin elk object data heeft op zijn eigen (zoals een gebruiker heeft een naam)
  • Gebruik een statische klasse als het is gewoon een tool die werkt op andere dingen (zoals bijvoorbeeld een syntax converter voor BB code naar HTML, het is niet een leven op zichzelf hebben)

(Ja, ik geef toe, heel erg overdreven vereenvoudigde …)

Een ding over statische methoden / klassen is dat ze niet testen eenheid te vergemakkelijken (althans in PHP, maar waarschijnlijk in andere talen ook).

Een ander ding over statische gegevens is dat slechts één exemplaar van het bestaat in het programma: als je MyClass :: $ mydata ingesteld op een bepaalde waarde ergens, zal het deze waarde te hebben, en het alleen maar, overal – Sprekend over de gebruiker, zou je in staat zijn om slechts één gebruiker te hebben – dat is niet zo geweldig, is het dan

Voor een blog systeem, wat kan ik zeggen? Er is niet veel ik zou als statische schrijven, eigenlijk, denk ik; misschien de DB-toegang klasse, maar waarschijnlijk niet, op het einde ^^


Antwoord 2, gezag 57%

De belangrijkste twee redenen tegen het gebruik van statische methoden zijn:

  • code met behulp van statische methoden is het moeilijk om testen
  • code met behulp van statische methoden is het moeilijk om uitbreiden

Het hebben van een statische methode oproep in een andere methode is eigenlijk nog erger dan het importeren van een globale variabele. In PHP, lessen zijn wereldwijde symbolen, dus elke keer dat u een statische methode u een beroep doen op een wereldwijde symbool (de naam van de klasse) noemen. Dit is een geval waarin de mondiale slecht is. Ik had problemen met dit soort benadering met enkele component van Zend Framework. Er zijn klassen die statische methode gesprekken (fabrieken) te gebruiken om te bouwen objecten. Het was onmogelijk voor mij om een ​​andere fabriek in om een ​​op maat gemaakte object terug te leveren aan die instantie. De oplossing voor dit probleem is om alleen gevallen gebruik en instace methoden en af ​​te dwingen eenlingen en dergelijke in het begin van het programma.

Miško Hevery , die werkt als een Agile Coach bij Google, heeft een interessante theorie, of liever advies, dat we het maken van een object tijd vanaf het moment dat moeten scheiden maken we gebruik van het object. Dus de levenscyclus van een programma is in twee gesplitst. Het eerste deel (de main()zeg methode let’s), die zorgen voor alle object bedrading in uw toepassing neemt en het deel dat het eigenlijke werk doet.

Dus in plaats van:

class HttpClient
{
    public function request()
    {
        return HttpResponse::build();
    }
}

We moeten liever doen:

class HttpClient
{
    private $httpResponseFactory;
    public function __construct($httpResponseFactory)
    {
        $this->httpResponseFactory = $httpResponseFactory;
    }
    public function request()
    {
        return $this->httpResponseFactory->build();
    }
}

En dan, in de index / hoofdpagina, zouden we doen (dit is de bedrading object stap, of de tijd om de grafiek van de gevallen te maken om te worden gebruikt door het programma):

$httpResponseFactory = new HttpResponseFactory;
$httpClient          = new HttpClient($httpResponseFactory);
$httpResponse        = $httpClient->request();

Het hoofdidee is om de afhankelijkheden uit je lessen te decouperen. Op deze manier is de code veel uitgebreider en, het belangrijkste deel voor mij, testbaar. Waarom is het belangrijker om testbaar te zijn? Omdat ik niet altijd bibliotheekcode schrijf, is dus niet zo belangrijk, maar de testbaarheid is belangrijk wanneer ik het refactoreren. Hoe dan ook, testable code levert meestal een uitbreidbare code op, dus het is niet echt een of of situatie.

Miško Hevery maakt ook een duidelijk onderscheid tussen singletons en singletons (met of zonder hoofdstad). Het verschil is heel eenvoudig. Singletons met een kleine letters “worden afgedwongen door de bedrading in de index / hoofd. U stimuleert een voorwerp van een klasse die niet het Singleton-patroon implementeert en zorgt ervoor dat u dat exemplaar alleen doorgeeft aan een andere voorschriften die het nodig heeft. Aan de andere kant is Singleton, met een hoofdstad “s” een implementatie van het klassieke (anti-) patroon. Eigenlijk een wereldwijde vermomming die niet veel gebruik heeft in de PHP-wereld. Ik heb er een niet meer gezien. Als u wilt dat een enkele DB-verbinding door al uw klassen wordt gebruikt, is het beter om het zo te doen:

$db = new DbConnection;
$users    = new UserCollection($db);
$posts    = new PostCollection($db);
$comments = new CommentsCollection($db);

Door het bovenstaande te doen, is het duidelijk dat we een Singleton hebben en we hebben ook een leuke manier om een ​​schijn of een stomp in onze tests te injecteren. Het is verrassend hoe het eenheidstests leiden tot een beter ontwerp. Maar het maakt veel zin wanneer je denkt dat tests je dwingen na te denken over de manier waarop je die code zou gebruiken.

/**
 * An example of a test using PHPUnit. The point is to see how easy it is to
 * pass the UserCollection constructor an alternative implementation of
 * DbCollection.
 */
class UserCollection extends PHPUnit_Framework_TestCase
{
    public function testGetAllComments()
    {
        $mockedMethods = array('query');
        $dbMock = $this->getMock('DbConnection', $mockedMethods);
        $dbMock->expects($this->any())
               ->method('query')
               ->will($this->returnValue(array('John', 'George')));
        $userCollection = new UserCollection($dbMock);
        $allUsers       = $userCollection->getAll();
        $this->assertEquals(array('John', 'George'), $allUsers);
    }
}

De enige situatie waarin ik zou gebruiken (en ik heb ze gebruikt om het JavaScript-prototype-object in PHP 5.3 te mimiceren) Statische leden zijn wanneer ik weet dat het respectieve veld dezelfde waardecross-instance heeft. Op dat moment kunt u een statische eigenschap gebruiken en misschien een paar statische getter / settermethoden. Hoe dan ook, vergeet niet om de mogelijkheid toe te voegen voor het overschrijven van het statische lid met een instantie-lid. Zend-framework gebruikte bijvoorbeeld een statische eigenschap om de naam van de DB-adapterklasse op te geven die wordt gebruikt in gevallen van Zend_Db_Table. Het is een tijdje geleden sinds ik ze heb gebruikt, dus het kan niet langer relevant zijn, maar dat is hoe ik het me herinner.

Statische methoden die niet omgaan met statische eigenschappen moeten functies zijn. PHP heeft functies en we moeten ze gebruiken.


Antwoord 3, Autoriteit 18%

Dus in PHP-statische kan worden toegepast op functies of variabelen. Niet-statische variabelen zijn vastgebonden aan een specifiek instantie van een klasse. Niet-statische methoden werken op een instantie van een klasse. Dus laten we een klasse vormen met de naam BlogPost.

titlezou een niet-statisch lid zijn. Het bevat de titel van die blogpost. Misschien hebben we ook een methode genaamd find_related(). Het is niet statisch omdat het informatie vereist van een specifiek instantie van de blog-postklasse.

Deze klasse ziet er zoiets uit:

class blog_post {
    public $title;
    public $my_dao;
    public function find_related() {
        $this->my_dao->find_all_with_title_words($this->title);
    }
}

Aan de andere kant, met behulp van statische functies, je zou kunnen schrijven een klasse als volgt uit:

class blog_post_helper {
    public static function find_related($blog_post) {
         // Do stuff.
    }
}

In dit geval, aangezien de functie is statisch en niet handelt op een bepaalde blog post, je moet gaan in de blog post als argument.

In wezen is dit een vraag over objectgeoriënteerd ontwerp. Uw klassen zijn de zelfstandige naamwoorden in het systeem, en de functies die werken op hen zijn de werkwoorden. Statische functies zijn procedurele. U passeert in het doel van de functies als argumenten.


Update: Ik zou ook toevoegen dat de beslissing is zelden tussen bijvoorbeeld methoden en statische methoden, en nog veel meer tussen het gebruik van klassen en het gebruik van associatieve arrays. Bijvoorbeeld, in een blogging app, moet u ofwel de blog te lezen uit de database en deze omzetten in objecten, of laat je ze in het resultaat set en behandelen hen als associatieve arrays. Dan schrijf je functies die associatieve arrays of lijsten van associatieve arrays als argumenten nemen.

In de OO scenario, u methoden op je BlogPostklasse die handelen op de individuele posten, en je statische methoden schrijven die inwerken op verzamelingen van berichten.


Antwoord 4, Autoriteit 11%

Is het allemaal gewoon stijl?

Een lange weg, ja. Je kunt prima object-georiënteerde programma’s te schrijven zonder ooit met statische leden. In feite zouden sommige mensen beweren dat statische leden een onzuiverheid in de eerste plaats. Ik stel voor dat – als een beginner in oop – je probeert om statische leden te vermijden allemaal samen. Het zal je dwingen in de richting van het schrijven in een objectgeoriënteerde in plaats van procedurele stijl.


Antwoord 5, Autoriteit 10%

Ik heb een andere benadering van de meeste antwoorden hier, vooral bij het gebruik van PHP. Ik denk dat alle klassen moeten statisch zijn, tenzij u een goede reden hebben waarom niet. Sommige van de “waarom niet” redenen zijn:

  • Je hebt meerdere exemplaren van de klasse
  • Je klas moet worden uitgebreid
  • Delen van je code kan niet de klasse variabelen te delen met andere delen

Laat mij een voorbeeld. Aangezien elke PHP-script produceert HTML-code, mijn framework heeft een html-schrijver klasse. Dit zorgt ervoor dat er geen andere klasse zal proberen om HTML schrijven want het is een gespecialiseerde taak die moet worden geconcentreerd in een enkele klasse.

Normaal gesproken, zou u gebruik maken van de html-klasse als volgt uit:

html::set_attribute('class','myclass');
html::tag('div');
$str=html::get_buffer();

Elke keer get_buffer () wordt aangeroepen, stelt alles zo dat de volgende klasse aan de html-schrijver begint te gebruiken in een bekende staat.

Al mijn statische klassen hebben een functie init (), die moet worden aangeroepen voordat de klasse wordt gebruikt voor de eerste keer. Dit is volgens afspraak dan noodzakelijk.

Het alternatief voor een statische klasse in dit geval is rommelig. Je zou niet willen elke klasse die nodig heeft om een ​​klein beetje van html schrijven te hebben om een ​​instantie van de html-schrijver te beheren.

Nu zal ik u een voorbeeld van wanneer geen statische klassen te gebruiken. Mijn vorm klasse beheert een lijst van vorm elementen zoals tekstinvoer, keuzelijsten en nog veel meer. Het wordt meestal gebruikt als volgt uit:

$form = new form(stuff here);
$form->add(new text(stuff here));
$form->add(new submit(stuff here));
$form->render(); // Creates the entire form using the html class

Er is geen manier om je kon dit te doen met statische klassen, vooral gezien het feit dat een deel van de constructeurs van elk toegevoegd klasse doen een hoop werk. Ook de keten van de erfenis voor alle elementen is vrij complex. Dus dit is een duidelijk voorbeeld waar statische klassen niet moet worden gebruikt.

De meeste nut klassen zoals die omzetten / formatteren strings zijn goede kandidaten voor het zijn een statische klasse. Mijn regel is simpel: alles gaat statisch in PHP, tenzij er is een reden waarom het niet mag.


Antwoord 6, Autoriteit 8%

“Het hebben van een statische methodeaanroep binnen een andere methode is eigenlijk erger dan het importeren van een globale variabele.” (definieer “slechter”)… en “Statische methoden die niet omgaan met statische eigenschappen zouden functies moeten zijn”.

Dit zijn beide behoorlijk ingrijpende uitspraken. Als ik een reeks functies heb die gerelateerd zijn aan het onderwerp, maar instantiegegevens zijn totaal ongepast, zou ik ze liever in een klasse hebben gedefinieerd en niet elk in de globale naamruimte. Ik gebruik gewoon de mechanica die beschikbaar is in PHP5 om

  • geef ze allemaal een naamruimte — vermijd eventuele naamconflicten
  • houd ze fysiek bij elkaar in plaats van verspreid te raken over een project — andere ontwikkelaars kunnen gemakkelijker vinden wat er al beschikbaar is en zullen minder snel het wiel opnieuw uitvinden
  • laat me class consts gebruiken in plaats van globale definities voor magische waarden

het is gewoon een handige manier om een ​​hogere cohesie en een lagere koppeling af te dwingen.

En FWIW — er bestaat niet zoiets, althans niet in PHP5, als “statische klassen”; methoden en eigenschappen kunnen statisch zijn. Om instantiëring van de klasse te voorkomen, kan men deze ook abstract verklaren.


Antwoord 7, autoriteit 6%

Vraag jezelf eerst af, wat gaat dit object voorstellen? Een objectinstantie is goed om op afzonderlijke sets dynamische gegevens te werken.

Een goed voorbeeld is de ORM- of database-abstractielaag. Mogelijk hebt u meerdere databaseverbindingen.

$db1 = new Db(array('host' => $host1, 'username' => $username1, 'password' => $password1));
$db2 = new Db(array('host' => $host2, 'username' => $username2, 'password' => $password2));

Deze twee verbindingen kunnen nu onafhankelijk van elkaar werken:

$someRecordsFromDb1 = $db1->getRows($selectStatement);
$someRecordsFromDb2 = $db2->getRows($selectStatement);

In dit pakket/de bibliotheek kunnen er nu andere klassen zijn, zoals Db_Row, enz. om een ​​specifieke rij weer te geven die wordt geretourneerd door een SELECT-instructie. Als deze klasse Db_Row een statische klasse was, zou dat veronderstellen dat u slechts één rij met gegevens in één database hebt en dat het onmogelijk zou zijn om te doen wat een objectinstantie zou kunnen. Met een instance kunt u nu een onbeperkt aantal rijen hebben in een onbeperkt aantal tabellen in een onbeperkt aantal databases. De enige beperking is de serverhardware ;).

Als de methode getRows op het Db-object bijvoorbeeld een array van Db_Row-objecten retourneert, kunt u nu op elke rij onafhankelijk van elkaar werken:

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;
    // now save that record/row
    $row->save();
}
foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

Een goed voorbeeld van een statische klasse is iets dat registervariabelen of sessievariabelen afhandelt, aangezien er maar één register of één sessie per gebruiker is.

In een deel van uw aanvraag:

Session::set('someVar', 'toThisValue');

En in een ander deel:

Session::get('someVar'); // returns 'toThisValue'

Aangezien er maar één gebruiker tegelijk per sessie zal zijn, heeft het geen zin om een ​​instantie voor de sessie te maken.

Ik hoop dat dit helpt, samen met de andere antwoorden om dingen op te helderen. Als een kanttekening, bekijk “cohesie” en “koppeling“. Ze schetsen een aantal zeer, zeer goede praktijken om te gebruiken bij het schrijven van uw code die van toepassing zijn op alle programmeertalen.


Antwoord 8, autoriteit 5%

Als je klasse statisch is, betekent dit dat je het object niet kunt doorgeven aan andere klassen (omdat er geen instantie mogelijk is), dus dat betekent dat al je klassen rechtstreeks die statische klasse zullen gebruiken, wat betekent dat je code nu nauw is gekoppeld met de klas.

Strakke koppeling maakt uw code minder herbruikbaar, kwetsbaar en vatbaar voor bugs. Je wilt statische klassen vermijden om de instantie van de klasse door te geven aan andere klassen.

En ja, dit is slechts een van de vele andere redenen waarvan sommige al zijn genoemd.


Antwoord 9, autoriteit 2%

Over het algemeen moet u lidvariabelen en lidfuncties gebruiken, tenzij het absoluut tussen alle instanties moet worden gedeeld of tenzij u een singleton maakt. Door lidgegevens en lidfuncties te gebruiken, kunt u uw functies hergebruiken voor meerdere verschillende soorten gegevens, terwijl u slechts één kopie van de gegevens kunt hebben waarop u werkt als u statische gegevens en functies gebruikt. Bovendien, hoewel niet zo van toepassing op PHP, leiden statische functies en gegevens ertoe dat code niet-herintredend is, terwijl klassegegevens herintreding vergemakkelijken.


Antwoord 10, autoriteit 2%

Ik zou willen zeggen dat er zeker een geval is waarin ik statische variabelen zou willen hebben in meertalige toepassingen.
Je zou een klas kunnen hebben waaraan je een taal doorgeeft (bijv. $_SESSION[‘language’]) en die op zijn beurt toegang heeft tot andere klassen die als volgt zijn ontworpen:

Srings.php //The main class to access
StringsENUS.php  //English/US 
StringsESAR.php  //Spanish/Argentina
//...etc

Het gebruik van Strings::getString(“somestring”) is een leuke manier om uw taalgebruik uit uw toepassing te abstraheren. Je zou het kunnen doen zoals je wilt, maar in dit geval werkt het vrij goed om elk strings-bestand constanten te hebben met stringwaarden die toegankelijk zijn voor de Strings-klasse.

Other episodes