Znate šta je problem - vi gledate OOP na način da tražite mjesto da ga negdje uglavite, samo zato jer se radi o "trendu", a ne o konkretnoj potrebi za koju vidite rješenje jednom od objektnih tehnika / design pattern-a. Netko je rekao da se sve može postići samo funkcijama - i to je tačno, ali na isti način kao što je sve moguće postići asemblerskim kodom (može i niže, ko želi).
Pustite sada nasljeđivanje, polimorfizam i ostale sitnice. Glavni razlog OOP-a je povećanje abstrakcije, i lakše sagledavanje na stvari - to je ono što treba biti motiv za sve. Pomenute tehnike su tu da ostvare taj motiv, ništa više. Abstrakcija koja se postiže micanjem na veći stepen razvoja (na objektni pristup sa funkcijskog) je neprocjeniva tehnika koja je omogućila software ovakvim kakav je danas; i da napomenem da pod tom vrstom software-a ne mislim na kernel-e sistema ili neke mission-critical procese sa veoma ograničenim resursima gdje je sve osim asemblera/C-a "preteško". Programi od nivoa naprednih dokument editora (kao MS Word) pa do ERP sistema bi bili nemogući za izvesti bez OOP-a.
Problem većine PHP programera sa shvatanjem OOP-a i racionalizaciom njegove primjene je u nedovoljnoj kompleksnosti njihovih projekata. Ruku na srce, većina ne piše iole komplikovanije enterprise sisteme, kamoli šta drugo. Lako je koristiti funkcijsko programiranje na bazi sa 5-10 tabela.
Šta OOP omogućuje?
OOP omogućuje da za početak particionišete (princip enkapsulacije) dijelove sistema tako da umjesto da vodite računa o 48 stvari odjednom, vi smanjite taj broj na recimo 5-6. Uzmite za primjer evo komunikaciju sa bazom podataka koju stalno spominjete. Bez OOP-a, vaš kod se svodi za CRUD (
Create,
Read,
Update,
Delete) funkcije od kojih svaka odrađuje neki dio posla. Uzmite za slučaj da imate bazu sa 40 tabela. To je ~160 funkcija. Uzmite da morate imati transakcijska ograničenja na određene radnje koje uključuju određene skupove tih funkcija (recimo, prebacivanja novca u banci s jednog računa na drugi uključuje upis u tabelu transakcija, te dva update-a u tabeli stanja racuna - sa jednog + na drugi -). Ovo bi morali odraditi tako da napravite novu funkciju koja obuhvata te 3 u transakcijski okvir sa BEGIN - COMMIT - ROLLBACK. To dodaje još 30-ak funkcija. Uzmite onda da odjednom morate voditi audit logove svih korisničkih radnji, svih transakcija. Gdje ćete to uraditi? Mjenjati tih svih 30 funkcija?
Nemojte samo sada reći, pa dobro - to se može prebaciti na stored procedure u bazu. Pozivanje tih stored procedura sa parametrima nije ništa drugo nego micanje problema na drugo mjesto plus uvođenje dodatne kompleksnosti razdvajanjem koda na dodatna dva sloja (iako, to je normalna praksa ako je potreba za time realna - kao u bankama gdje je sigurnost podatka na prvom mjestu).
Particionisanje se radi pomoću par tehnika. Nema smisla objašnjavati šta znači referencirati jedan objekt iz drugog (asocijacije itd...). Najvažnija tehnika je definisanje granica vidljivošću podataka i funkcija. Private / public / protected oznake postoje ne radi otežavanja stvari, nego olakšavanja programiranja uvođenjem konceptualih granica u kod. Lako je vama sa 10 funkcija znati koju treba kada pozivati. Uzmite da bilo koji teži scenario zahtjeva da se slijedi tačno definisan postupak za neku radnju. Uzmite da neki objekt HTMLPage ima funkcije (mrzim ovo zvati "funkcije" kad je u OO svijetu pravilno reći metode, ali eto...) CreateHeader(), CreateBody(), CreateFooter(), bez parametara, koje sve same znaju odraditi. Da bi sve ispravno radilo, potrebno je pozvati ih u tome redoslijedu. Ko kaže da se neće naći neki rookie programer koji će ih pozvati nepravilno - i unijeti bug u program? Ko kaže da kada bude postojalo 2000 funkcija kroz 40 file-ova da nikada neće biti situacija da se nešto pozove nepravilno? Ograničenja koja sami postavljamo u OOP-u pomažu da se takve vrste grešaka svedu na minimum. Stavite ove tri funkcije na private vidljivost, tako da ih kod van klase ne može pozivati. Napravite public funkciju koja poziva ove tri u pravilnom redoslijedu. Public funkcija je vidljiva vanjskom svijetu, private nisu - te zato nitko ih ne može niti direktno zloupotrijebiti.
Upotrebom particionisanja stvarate black-box kocke koda za čije korištenje ne morate znati apsolutno ništa o njima. Za shvatanje toga primjenom OOP-a, ne morate koristiti sve OOP tehnike (ne treba vam niti nasljeđivanje, niti polimorfizam). Jedan od najosnovnijih design pattern-a je layering, tj. podjela koda u slojeve. Ako svaki sloj predstavimo objektima, i u svakome pozivamo samo objekte sloja ispod - dobiva se ogromna organizacija koda, a o manjoj mogućnosti grešaka i preglednijeg koda da se ne priča. UI sloj može pozivati poslovnu logiku, ona može pozivati sloj za komunikaciju sa bazom podataka, itd... Čak i ako sve ostavite u funkcijama, kad ih barem stavite u zajednički objekt, osiguravate da onaj koji ih poziva zna šta radi, jer mora instancirati taj "layer".
Netko je naveo da se kod može organizirati i jednostavno kroz file-ove i include naredbe. Istina, samo što taj pristup nema niti jednu od ostalih OOP osobina osim smanjenja veličine koda (i to samo djelomičnog smanjenja). Time ne dobivate nikakvu abstrakciju, ne možete postaviti nikakva ograničenja, te nema polimorfizma i nasljeđivanja, što je najjača OOP osobina.
Govoreći o polimorfizmu i nasljeđivanju, da nastavim s njima na primjeru rada sa bazom podataka. Pravilnom upotrebom osnovnog modela nasljeđivanja možete napraviti po objekt za svaki entitet koji imate u bazi. Prvo na što ćete naići je osobina da svaki taj entitet (tabela) ima ID. Zašto to onda ne prebaciti u zajedničku nad klasu? Jedini varijabilni parametar nad-klase može biti ime tabele entiteta. Funkcija za dobavljanje sljedećeg ID-a iz baze je ovisna u većini scenarija samo o imenu tabele u kojoj se traži ID, što je kvalificira da ide u nad-klasu. U složenijem scenariju, kada to nije dovoljno, ili kad se koristi neka složenija tehnika, napravite objekt IdGenerator, koji ima funkciju Generate(). Nasljeđivanjem napravite objekte kojima je IdGenerator nad klasa, i od kojih svaka implementira funkciju Generate() prema svome određenom scenariju. Jedna može dobavljati ID preko MAX() SQL funkcije. Jedna može koristiti posebnu tabelu samo za ID-eve. Jedna može iskoristiti SQL Server ili Oracle pogodnosti. Mogućnosti su neograničene. Ona naša prva nad-klasa za sve entitete, koja sadrži funkciju za generisanjeg sljedećeg ID-a, može jednostavno delegirati taj posao na konkretnu instancu IdGenerator klase, što nije ništa drugo nego najjednostavnija primjena polimorfizma.
Drugi primjer je nešto što nedostaje PHP-u, a to je objektna hijerarhija za mnoge očite stvari. Recimo, u PHP-u ja ne mogu da se oslonim da postoji neka funkcija koja će se automatski pozvati kada je potreban string tip podataka. Jezici kao C# ili Java imaju realizacije ToString() funkcije koja je implementirana u baznoj Object klasi, koju svaka klasa implicitno nasljeđuje (znači, nasljeđivanje + polimorfizam). PHP nema DateTime objekte, pa da mogu raditi sa vremenskim zonama, ili da ih mogu oduzimati da dobijem TimeSpan objekt koji sadrži podatke oduzimanja dva datuma. Primjera je hrpa.
Čak i bez sofisticiranih alata, za ne-presložene projekte, moguće je da sami napravite osnovni framework za manipulaciju tabelama u bazi podataka, koji se zasniva na jednostavnom nasljeđivanju entitet klase, i dopunjavanju imena tabele, i polja u bazi podataka. ORM-i rade to isto, samo sa još jednim slojem između, i gomilom ostalih mogućnosti kao što su Identity Maps, Lazy Loading, Query objekti, itd...
Pošto ovaj post nije pokušaj objašnjavanja nekome tačno gdje i kako može primjeniti OOP - uzmite fino knjigu
"Design Patterns: Elements of Reusable Object-Oriented Software" i pročitajte je od korica do korica sa vježbanjem i pokušavanjem dubokog razumijevanja svakog primjera. Ja nisam upotrebljavao OOP ni 20% dok nisam počeo čitati ovu knjigu. Sada ne shvatam kako to nisam prije znao - jednostavno dobijete taj osjećaj povezanoti sa OOP pristupom da ništa drugo nema smisla.
Što se tiče konkretnih postova u ovoj temi, gledanje OOP-a kao broj parametara u metodama je loše. Nitko vas ne ograničava da imate metodu sa 5 parametara, niti metodu bez i jednog. Cilj je praviti kod koji se ravna prema
SOLID principima, a to je već nešto što zahtjeva mnogo i mnogo rada, truda i volje za pravilnim OOP-om. Iz ovih principa dobivaju se svi design pattern-i od kojih eto za vas web programere, MVC je neprocjenjiv.
Principi koji se isto stalno spominju, i prožimaju s ostalima, su tight i loose coupling. Poenta je imati što manji broj dependency-a među objektima, tako da izmjena na jednome ne pravi ripple-effect na ostalima. Broj parametara naravno pomaže u tome, ali ne može se jednostavno reći sad ću praviti funkcije bez parametara, i to je to.
BTW, OOP nije niti blizu kraja, nakon njega imate TDD, pa dalje da se ne priča ...

A sve je u svrhu povećanja abstraktnosti, osiguravanja od bug-ova, i što kvalitetnijeg razvoja software-a...
My programs don’t have bugs, they just develop random features.