Type hinting in PHP

Door AtleX op zondag 30 december 2007 18:24 - Reacties (9)
Categorie: PHP, Views: 5.803

PHP wordt voornamelijk verguisd of geprezen, net wie het zegt, om zijn eenvoud in gebruik. Een belangrijk onderdeel daarvan weak typing, je hoeft je immers geen zorgen te maken over de juiste types maar je kunt gewoon lekker door programmeren. PHP gaat daar best ver in, zo komt er uit het volgende stuk code gewoon 5.

PHP:
1
echo "3 schapen" + "1 schaap" + 1.0;


Een nadeel is dat je als programmeur geen flauw idee hebt wat je binnen gaat krijgen in je methodes via parameters, en zelfs public members zijn niet meer te vertrouwen als je ze niet read-only maakt. Daardoor is de programmeur haast gedwongen om in elke methode uitgebreide checks op type te schrijven, met bijvoorbeeld is_int(), is_string() of 1 van de andere is_*() functies.

Bij PHP 5 is dit probleem gedeeltelijk aangepast, door type hinting te introduceren. Type hinting lijkt op de aloude strong-typed parameters in talen als C#, en forceert dat een parameter van een bepaald type moet zijn. Dat bespaart een programmeur veel tijd en werk, doordat er binnen de methodes zelf geen controles meer geschreven hoeven worden. Naast het feit dat dit geld bespaart betekent minder code natuurlijk ook minder kans op bugs, en daarnaast wordt de code leesbaarder doordat de nutteloze if()-jes voor de controles niet meer nodig zijn.

Genoeg over de theorie, nu wat voorbeelden. In het eerste voorbeeld is meer een voorbeeld van de onzekere situatie als er geen type hinting gebruikt word, met demonstraties waarom dat fout gaat. Neem bijvoorbeeld de volgende code:

PHP:
1
2
3
4
5
6
7
8
9
class Foo
{
    private $Bar; // Only Bar objects
    
    public function __construct($param)
    {
        $this->Bar = $param;
    }
}


Als we er nu 3 objecten van aanmaken wordt het probleem duidelijk:

PHP:
1
2
3
4
$foo = array();
$foo[] = new Foo(1);
$foo[] = new Foo("schaap");
$foo[] = new Foo(0.1);


Het is nu absoluut niet zeker wat het type van de private member $Bar is Sterker nog, we verwachten daar een Bar object maar we kunnen er niet meer vanuit gaan dat die erin staat. Bij het uitvoeren van een bewerking op Bar, bijvoorbeeld $this->Bar->Bogus(), zou dat een mooie error op kunnen leveren.

In principe zijn hiervoor 2 oplossingen, de eerste komt neer op alsnog een if() gebruiken, en de 2e is type hinting. Het voordeel van de eerste is dat deze ook werkt in PHP4, dus voor de nostalgische programmeurs onder ons heb ik een voorbeeld:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
class Foo
{
    var $Bar;
    
    function Foo($bar)
    {
        if (get_class($bar) === "Bar")
            $this->Bar = $bar;
        else
            trigger_error("\$bar must be a Bar object");
    }
}


Dit heeft 1 groot nadeel, buiten het feit dat het antieke PHP4 code is. Het is namelijk no steeds noodzakelijk om een if() neer te zetten met een check, wat zoals eerder beschreven alleen maar tijd en dus geld kost.

PHP5's type hinting is wat dat betreft flink makkelijker, sterker nog, er is maar 1 extra woordje nodig in plaats van een if().

PHP:
1
2
3
4
5
6
7
8
9
class Foo
{
    private $Bar;
    
    public function __construct(Bar $bar)
    {
        $this->Bar = $bar;
    }
}


Zoals de oplettende lezer al heeft gezien is er nu een type gespecificeerd bij de parameter, en is er geen check meer nodig. In dit voorbeeld bespaart het maar 3 regels code, maar het is wel duidelijk dat dit bij 5 parameters al 5 checks bespaart. Ook levert dit een keiharde catchable fatal error op als een programmeur een object van het verkeerde type meegeeft. In tegenstelling tot de PHP4 oplossing is deze foutmelding absoluut niet te negeren, en ook verschijnt de message altijd ongeacht het niveau van error_reporting (ok, E_NONE onderdrukt 'm, maar geen enkel weldenkend persoon gebruikt die in een development environment).

Heeft type hinting dan alleen maar voordelen? Nee, absoluut niet. Het is namelijk nog niet af. Op de meeste types van php, zoals string, float, bool & int, is niet te controleren. Sterker nog, alleen objecten en array's kunnen maar gechecked worden door deze methode. Voor strings e.d. zijn er nog steeds de aloude is_*() functies noodzakelijk. Ik hoop dat dit mankement nog aangepakt wordt in toekomstige PHP versies, maar tot die tijd kan het in ieder geval al heel wat tijd en hoofdbrekens besparen.

Volgende: Benchmarks van mijn framework (1) 12-'07 Benchmarks van mijn framework (1)
Volgende: Merry Christmas 12-'07 Merry Christmas

Reacties


Door Tweakers user MikeN, maandag 31 december 2007 23:51

De vraag is dan alleen of strong typing echt zo belangrijk is. Er zijn hele discussies over en overtuigd voor en tegenstanders van beide fronten, maar in mijn ogen heb je aan zo'n halve oplossing als PHP biedt al helemaal niets. Je gooit op zo'n moment namelijk alle voordelen van weak typing weg (kijk hoe Ruby of Python programmeurs omgaan met de weak typing, het geeft je vaak juist meer mogelijkheden, hergebruik van methodes voor verschillende data types, duck typing enz.) terwijl je de voordelen van strong typing maar deels in huis haalt.

Door Tweakers user AtleX, dinsdag 1 januari 2008 00:26

Persoonlijk vind ik strong typing wel prettig, en wat mij betreft mag het zo snel mogelijk in PHP gebouwd worden. Je argument dat je nu 1 methode voor verschillende types kunt gebruiken bots nu een beetje met je opmerking dat PHP nu een halve oplossing bied. 1 Methode voor meerdere types is een slappe overloading cloon, wat de code niet echt duidelijk maakt. pe

In het geval dat je methode gewoon 1 type wilt hebben is type hinting gewoon handig, omdat er minder code voor nodig is. Ik denk dat je dat met me eens bent?

Door Tweakers user MikeN, dinsdag 1 januari 2008 00:57

Mja, ik heb net het een en ander mixed up.Namelijk strong/weak versus static/dynamic typing. De discussie lijkt hier voornamelijk static versus dynamic typing (een methode met meerdere types aan kunnen roepen valt daaronder) en niet strong versus weak typing (een object doodleuk een extra attribuut kunnen geven valt daaronder).

Op het moment dat je maar 1 type wil hebben kan type hinting handig zijn, de vraag is echter juist of je wel zo moet denken, iedere Ruby of Python tutorial zal je de exacte details en voorbeelden kunnen geven. En zeg nou zelf, wat is nou het probleem als er een ander object naar binnen komt? Dat het kapot gaat? Dat gaat het met static typing ook, alleen dan tijdens het compilen.

De volgende url biedt volgens mij wel een redelijk duidelijk overzicht btw: http://split-s.blogspot.c...staticdynamic-typing.html

Door Tweakers user AtleX, dinsdag 1 januari 2008 09:19

Interessante link. :) En uit je reactie merk ik wel dat het meer een kwestie van voorkeur is. Ik zelf vind type hinting makkelijk, als ik maar 1 soort object wil ontvangen in mijn methode. Jij bent blijkbaar een Ruby/Python fan, en houd er andere ideeŽn op na. :)

Je hebt gelijk dat het hoe dan ook kapot gaat, maar er is een subtiel verschil hoe het kapot gaat. Als je type hinting gebruikt en je geeft een object van het verkeerde type mee krijg je een catchable fatal error terug. Je applicatie stopt er dus op dat punt mee, er wordt dus geen code meer uitgevoerd tenzij je zelf de error afhandelt. Als je geen type hinting gebruikt krijg je afaik een warning, als de programmeur die jouw code gebruikt z'n error level niet hoog genoeg heeft staan ziet hij die dus niet. Bij het uitvoeren van de code gaat hij bij error dus ook gewoon door, met het risico op inconsistente gegevens etc.

Door Tweakers user PrisonerOfPain, zondag 6 januari 2008 01:55

Type hinting is allemaal leuk en aardig maar het kan best verraderlijk zijn.


PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Foo{
   public function bar();
}

class SomeClass implements Foo{
   public function bar();
   public function foo_bar();
}

function test(Foo $foo)
{
   $foo->foo_bar();
   // foo_bar is niet in de interface gedefinieerd 
   // maar kan toch aangeroepen worden. Iets om
   // in het achterhoofd te houden.
}



Ook kun je array type-hinten, maar dat werkt niet zodra je de SPL interface voor ArrayObject implementeerd; dan dien je ArrayObject te type-hinten.

Maar behalve dat is het een mooie manier om wat simpele dingetjes af te dwingen en te documenteren.

Door Tweakers user Snake, maandag 31 maart 2008 02:59

@PrisonerOfPain: Hoe the hell kan dat? Foo heeft geen foo_bar(); methode, en toch kan het?

Ik begin PHP viezer en viezer te vinden.

Door Tweakers user g4wx3, woensdag 2 april 2008 19:47

Gelukkig hoe je alleen input te controleren, je eigen programma heb je onder controle (hopelijk toch)
Input is heel makkelijk te controleren, snap niet waarom er zoveel heisa rond word gemaakt (SQL injectins enzo)
Bij random input controleren even de inhoud filteren
Bij niet random input, ALLES, behalve textarea,input type=text/passwoord kun je de input testen aan alle mogelijke voorwoorden, komt er geen overeen, dan krijgt de gebruiker een foutmelding
Ik ben blij dat PHP loose type is(of hoe je het ook noemt)
Het bespaart me veel tijd om eerst alle variabelen te definiŽren.
Zelf maakte ik een kenbaar wat voor type een variable is met 1 letter (wel niet gestandaardiseerd, geluk van alleen programeren, als hobby{voor een beetje geld})

BTW: 1 ding wat ik "stom" vind bij PHP is het gebruik van '->', ipv '.'
Vind het onhandig, onoverzichtelijker, verwarrend (=>) en ben er niet aan gewend.
type bijvoorbeeld eens snel '...' en '->->->', doe dat nu maal het aantal keer dat je het gebruikt...

Door Tweakers user AtleX, donderdag 3 april 2008 22:42

Moet je eens C++ gaan programmeren. ;) Daar gebruik je zowel punten als pijltjes (->), en zeker in het begin is dat behoorlijk verwarrend.

Door Tweakers user 535217, woensdag 28 augustus 2013 16:11

Nuttig dit! Maar ook ik begin behoorlijk af te knappen op PHP!

Ps. Kijk ook eens op jouw <a hfref=”http://www.jouwictvacature.nl”>ictvacature</a>!!

Reageren is niet meer mogelijk