Autor wpisu: batman, dodany: 25.02.2011 08:00, tagi: php
Eclipse towarzyszył mi przez całą moją drogę programisty PHP. Poza krótkimi skokami w bok z Netbeansem oraz szybkimi akcjami z Notepad++ oraz PSPad, Eclipse był zawsze ze mną. Szerokie spektrum zastosowania utwierdzało mnie w przekonaniu, iż nie ma lepszej platformy dla programisty. Oprócz PHP, Eclipse (a raczej liczne jego odmiany) pozwalał mi na pracę z Flexem, Windows Azure, AIR (w JavaScript), a nawet przez bardzo krótką chwilę z Javą. Niedawno przekonałem się jak bardzo byłem w błędzie. Największą bolączką Eclipse’a jest jego mułowatość. Nie raz zdarzyło mu się zawiesić na podpowiadaniu składni, a instalacja kolejnych pluginów, negatywnie odbijała się na i tak nienajlepszej wydajności. Do tego wszystkiego dochodzi ogromne zapotrzebowanie na pamięć oraz dosyć wysoka awaryjność. Jednym słowem – tragedia. Dlaczego więc uparcie siedziałem na Eclipse? Ponieważ mimo swoich wad, był najlepszym IDE dla programisty PHP.
Był, gdyż przełamałem niechęć do PhpStorm (kolejne IDE napisane w Javie) i z pełną odpowiedzialnością mogę napisać, że jest to najlepsze jak do tej pory IDE dla PHP na jakim przyszło mi pracować. Wprawdzie testuję je raptem od tygodnia, jednak nie zdarzyło mu się jeszcze, przywiesić na podpowiadaniu składni. Każdego dnia odkrywam kolejne interesujące funkcjonalności, a ekranu z ustawieniami nie przejrzałem nawet do połowy.
Dlaczego PhpStorm jest taki rewelacyjny? Jego zalety zebrałem w punktach. Oto one:
- Zużywa mniej pamięci.
- Podpowiadanie składni jest niesamowicie szybkie i jeszcze mi się nie zamuliło.
- Podpowiadane są również klucze w tablicach.
- Zamiast pisać całą nazwę klasy, wystarczy napisać pierwsze litery członów jej nazwy. Czyli zamiast Zend_Form_Element_Text, wystarczy że napiszemy ZFET, a resztą zajmie się podpowiadanie składni.
- Wsparcie dla narzędzi wiersza poleceń (Zend Framework, Symfony oraz własne narzędzia). Możemy z poziomu IDE korzystać z Zend_Tool. Co więcej, PhpStorm podpowiada składnię poleceń.
- Generowanie PHPDoc wraz z typami. Typy określane są na podstawie domyślnych wartości w argumentach funkcji oraz na podstawie typu zmiennej zwracanej przez funkcję.
- Jeśli chcemy przejść do jakiegoś pliku, nie musimy już go szukać w drzewie. Wystarczy, że zastosujemy ten sam mechanizm, co w przypadku podpowiadania składni, czyli napiszemy pierwsze litery z członów nazwy klasy.
- wbudowane mechanizmy do obsługi systemów kontroli wersji – CVS, SVN, Git, Mercurial
- możliwość integracji z JIRA, Redmine, GitHub
- wbudowany debuger
- możliwość wdrożenia projektu na serwer FTP/SFTP
- możliwość połączenia się bazą danych
- refaktoryzacja kodu
- walidacja kodu pod kątem ilości argumentów przekazanych do funkcji/metody oraz implementacji abstrakcyjnych metod
- wbudowany wiersz poleceń
Już. Trochę tego się uzbierało jak na tydzień testowania. Pewnie zastanawiacie się gdzie jest haczyk? PhpStorm nie jest darmowy. Licencja dla pojedynczego dewelopera kosztuje około 350 złotych. Warto jednak wydać te pieniądze na coś tak dobrego jak PhpStorm.
Czy to oznacza, że na dobre pożegnałem się z Eclipse? Nie. Z Eclipse będę korzystał podczas pracy nad projektami związanymi z Windows Azure, chociaż na pewno spróbuję przenieść większość (a może i wszystkie) prac na PhpStorm. Przesiadki na pewno nie uda mi się zrobić z Flash Buildera, ale o tym napiszę przy innej okazji.
Podsumowując. Jeśli zależy wam na dobrym IDE, za stosunkowo niewielką cenę, zainteresujcie się PhpStorm. Nie musicie go od razu kupować. Przez 30 dni można testować jego możliwości za darmo w ramach triala.
Autor wpisu: sokzzuka, dodany: 24.02.2011 14:35, tagi: php
Wykonując dzisiaj taski w pracy, natrafiłem na ciekawą rzecz, task, z wklejonym komunikatem o treści (imiona klas zostały zmienione ze względu na prośbę zainteresowanych):
Fatal error: Cannot access private property Foo::$foo in /home/www/example/Bar.php on line 75
Pierwsze co zrobiłem, to oczywiście zajrzałem do pliku Bar.php i linie 75, zastałem coś w rodzaju:
public function init(){ $this->foo = 'foofoo'; }
Oczywiście pierwsze co mi przyszło do głowy to „pewnie w klasie w hierarchii wyżej jest ta zmienna zadeklarowana jako private”. Zacząłem przebijać się przez hierarchię klas i ku mojemu zdziwieniu deklaracji „private $foo;” nie znalazłem. Kilka razy rzuciłem kolegę dyżurnym pluszowym krabem i wpadł mi do głowy pomysł – zajrzę do kodu klasy Foo.
Zajrzałem i spostrzegłem, że wywołuje ona parent::init() z klasy Bar. Następnie zauważyłem, że ma zdeklarowane w swoim ciele szukane „private $foo”. Szybko zmieniłem private na protected i zadziałało.
Jakie z tego płyną wnioski ? Po pierwsze, warto czasami rzucić kogoś krabem. Po drugie, kwalifikatory widoczności działają w obie strony hierarchii klas. Po trzecie – jak mówi stare chińskie przysłowie – rzeka płynie tylko w jedną stronę, a jak płynie w dwie to odstaw LSD .
Autor wpisu: l3l0, dodany: 23.02.2011 21:06, tagi: php
Ostatnio zainteresowałem się metodologią tworzenia oprogramowania BDD (Behavior Driven Development – Programowanie sterowane zachowaniem). Jest to stosunkowo nowe podejście wprowadzone około 2003 roku przez Dana Northa (polecam: http://dannorth.net/introducing-bdd/).
O co to chodzi w tym całym BDD?
Opisze jak to rozumiem. Zaczynamy od określenia i identyfikacji wymagań biznesowych klienta jako “historyjek” które będą zrozumiałe dla każdego. Do “historyjek” dodajemy kryteria akceptacji, dzięki którym możemy powiedzieć kiedy nasza praca jest skończona. Nasze historyjki są zapisane w formacie zrozumiałym dla człowieka jednak powinny być też testami czyli powinny być wykonywalne i automatyczne. Tak zdefiniowane testy/zachowania są zarazem bardzo dobrą dokumentacją. Myślę że ta metodologia pomaga nam (ludziom związanym z tworzeniem oprogramowania) lepiej zrozumieć idee którą klient ma w głowie. Jeszcze do nie dawna w PHP nie było żadnego frameworka który pozwalał by używać tej metodologi, jednak na szczęście powstał behat który wzorowany jest na frameworku “cucumber” rubiego (który moim zdaniem jest całkiem zgrabną implementacją BDD). Moim zdaniem BDD może bardzo pomóc w tworzeniu dobrego oprogramowania. W najbliższym okresie mam zamiar bardziej zapoznać się z behatem od strony praktycznej. Na pewno podzielę się wynikami.
Autor wpisu: batman, dodany: 19.02.2011 08:00, tagi: css, javascript, php, jquery
Czym jest cheet sheat raczej tłumaczyć nie trzeba. Niejednokrotnie zerkałem na tablicę korkową/ścianę karton-gips naszpikowaną licznymi zadrukowanymi kartkami w celu znalezienia tej jednej jedynej, zawierającej odpowiedź na moje pytanie. Ściągawki są szybsze nawet od Google – zawsze pod ręką, nie wymagają do działa dostępu do Internetu (bez prądu też doskonale sobie radzą), zazwyczaj wystarczy rzut oka, by znaleźć rozwiązanie problemu.
Kilka dni temu Wookieb podesłał do mnie linka prowadzącego do strony zatytułowanej 100 + Must Have Cheat Sheets and Quick References For Web Designers and Developers. Nazwa mówi sama za siebie. Setka (a nawet więcej) obowiązkowych ściągawek, bez których żywot developera to droga przez mękę.
Nie przejrzałem wszystkich ściągawek, jednak po sprawdzeniu kilku najbardziej mnie interesujących, śmiało mogę napisać, iż tytuł nie został napisany na wyrost.
Co ciekawego znajdziemy na ściągawkach? Oto lista najciekawszych zagadnień:
- CSS3
- HTML5
- WordPress
- PHP
- jQuery
- czcionki
- Adobe AIR
Miłej lektury.
Autor wpisu: sokzzuka, dodany: 18.02.2011 13:43, tagi: javascript, php
Jedną z największych zalet jak i wad Javascriptu jest jego ogromna elastyczność i prostota. Dlaczego zalet jak i wad ? Dzięki elastyczności możemy więcej. Jednak z drugiej strony, możliwość rozwiązania jakiegoś problemu na kilka sposobów zmniejsza rozumienie kodu. Prostota i unifikacja JS wokół konceptu funkcji z jednej strony umożliwia wykorzystanie jednego mechanizmu enkapsulacji w wielu kontekstach. Natomiast z drugiej jest przez wielu nierozumiana, zwłaszcza przez osoby przyzwyczajone do języków gdzie występuje wiele słów kluczowych, przy pomocy których owy mechanizm jest realizowany. Elastyczność JS pozwala nam na takie zabawy, jak implementację własnego modelu obiektowego w efektywny sposób. Jakie cechy JS wspomagają ten proces ?
- Obiekty anonimowe
- Funkcja ‘__noSuchMethod__’ (odpowiednik __call w php)
- Funkcje anonimowe i domknięcia leksykalne
Tak na prawdę, przy pomocy JS można zaimplementować dowolną odmianę modelu obiektowego, który znajduję się w innych językach. Zarówno modele oparte na klasach, metaklasach, ich wariacje jak i na prototypach – które są wbudowane w JS. W tym artykule, który ma charakter badawczo – eksperymentalny chciałbym po pierwsze przedstawić model obiektowy jaki wymyśliłem, a po drugie jego implementację przy użyciu ww. listy cech języka. Mam nadzieje, że artykuł was zainteresuje oraz zainspiruje do podobnych eksperymentów .
Skoro wiemy już jakiś środków użyjemy, należałoby postawić pytanie – co chcemy osiągnąć ?
Model obiektowy, który chciałbym zaimplementować będzie starał naśladować rzeczywistość. Założenia:
- Obiekty tworzone są w fabrykach
- Fabryki tworzą obiekty poprzez komponowanie ich z różnych elementów wg. planów / foremek
- Foremki są z natury niezmienne, ale można komponować z ich elementów nowe wzory wg uznania (można w ten sposób zaimplementować coś o funkcjonalności wielodziedzieczenia)
- Każdy obiekt po opuszczeniu fabryki żyje własnym życiem i przez swój cykl istnienia może diametralnie się zmienić w stosunku do swojego wzorca
Myślę, że założenia są dość logiczne i odzwierciedlają cykl jaki przechodzą właściwie wszystkie realnie istniejące obiekty na naszej planecie. Żeby nie być gołosłownym podam najbardziej oczywisty przykład – Samochód.
- Samochód jest tworzony w fabryce
- Fabryka tworzy samochód poprzez komponowanie go z różnych elementów (silnik, koła, skrzynia etc) wg projektu.
- Projekt samochodu jest raczej niezmienny, a jeżeli coś jest zmieniane to nazywa się to nowym modelem
- Samochód po opuszczeniu fabryki może trafić w ręce różnych ciekawych ludzi którzy np. poddadzą go wiejskiemu tuningowi, wtedy na 100% nie będzie wyglądał tak jak go projektant narysował
Czas na kod! Na początek – plan/foremka/template:
var fooTemplate = { state: { foo: { value: 1 } }, behavior: { incrementFoo: { scope: 'public', value: function(self){ self.state.foo++ console.log (self.state.foo, 'incrementFoo'); } }, decrementFoo: { scope: 'internal', value: function(self){ self.state.foo--; console.log (self.state.foo); } } } }
Template został zadeklarowany jako anonimowy obiekt przypisany do zmiennej „fooTemplate”. Wewnątrz niego trzymamy metadane dotyczące tego jak skonstruować działające „coś”. Zmienne oznaczone są jako „state”, natomiast metody jako „behavior”. Każdy element z oprócz domyślnej wartości (value) posiada różne adnotacje. Zakładam, że wszystkie zmienne obiektu są prywatne. Natomiast metody, mogą być publiczne, albo prywatne (odpowiednio public i internal). Oczywiście można dodać różne inne adnotacje wzorem tych z Javy albo C#. Każda metoda jako pierwszy argument przyjmuje „self” – wewnętrzną referencję do obiektu, odpowiednik „this”.
Kolejnym rzeczą jaka będzie nam potrzebna to fabryka obiektów, która będzie wiedziała jak z template’u stworzyć obiekt. Dla takiego rodzaju template’u, jak wyżej zaprezentowany stworzyłem fabrykę w postaci funkcji „genericFactory”:
function genericFactory(template){ var self = { state: {}, behavior: { 'public': {}, 'internal': {} } }; for(var i in template.state){ self.state[i] = template.state[i].value } for(var i in template.behavior){ if(template.behavior[i].scope == 'public'){ self.behavior['public'][i] = template.behavior[i]['value'] } else { self.behavior['internal'][i] = template.behavior[i]['value'] } } function obj(){ this.__noSuchMethod__ = function __noSuchMethod__(id, args){ if(self.behavior['public'][id] != undefined){ args.unshift(self); return self.behavior['public'][id].apply(this, args); } throw 'No such method!' } } return new obj; }
Przetwarza ona template na konkretną instancję obiektu oraz enkapsuluje go w obiekcie „obj”. Obiekt „obj” posiada jedną metodę „__noSuchMethod__”. Jest ona odpowiednikiem „__call” w PHP. Sprawdza ona, czy metoda, która chcemy wywołać z obiektu jest możliwa do wywołania (jej scope jest „public”). Jeżeli tak, to jest wywoływana i zwracany jest efekt jej działania.
Jak już pisałem, efektem takiego podejścia do tworzenia obiektów jest możliwość zasymulowania wielodziedziczenia. Potrzebne będą nam do tego – jeszcze jeden template, oraz funkcja miksująca:
Autor wpisu: Śpiechu, dodany: 18.02.2011 00:52, tagi: php
Począwszy od wersji 5.3.0 dostaliśmy nową fajną funkcję do czarowania w PHP. Do tej pory jeżeli chcieliśmy wywoływać funkcję, która nie istnieje, musieliśmy używać __call
. Teraz dodano __callStatic
. Przyznam się, że jakoś mi umknęła. Jak sama nazwa mówi, służy do wywoływania nieistniejących metod statycznych. Pomyślałem, że warto wymyślić dla niej jakieś sensowne zadanie.
W ilu miejscach kodu sprawdzacie wielokrotnie zmienne czy nie są nulami, czy nie są puste, a jak spełnią te dwa warunki, to czy są liczbami całkowitymi i czy nie są większe niż np. 5? Sprawdzenie tych wszystkich warunków powoduje masę IFów. Nie lepiej byłoby sprawdzać tak
if (Walidator::check_notNull_notEmpty_isInt_gt5($zmienna)) { // poprawna wartosc }
Fajne, co? Bez tworzenia obiektów, złożonych funkcji warunkowych itp. Dla setterów jak znalazł Kolejne elementy nazwy zawężają warunek poprawności.
Klasa powstała w ok. 1 godz., dlatego używajcie na własną odpowiedzialność. W ciągu kilku dni wrzucę klasę na githuba i trochę potestuję w kierunku błędów, dorzucę kilka interesujących warunków itp. Może się komuś przyda.
<?php class Walidator { /** * Reaguje na funkcje rozpoczynajace sie od 'check_'. * Jako separatora uzywac znaku _ * @param string $name nazwa nieisniejacej funkcji * @param array $args podane parametry * @return bool */ public static function __callStatic($name, $args) { if (stripos($name, 'check_') === 0) { // obcinamy poczatek $name = substr($name, 6); // rozdzielamy skladowe nazwy $extractedNames = explode('_', $name); // przelatujemy po wszystkich rozdzielonych funkcjach foreach($extractedNames as $funcName) { // rozpracowujemy nazwe funkcji $funcName = self::extractFunction($funcName); // sprawdzamy czy rozpracowana funkcja istnieje if (!method_exists(__CLASS__, $funcName['funkcja'])) { throw new Exception("Funkcja {$funcName} nie istnieje!"); } // sprawdzamy czy w parametrze podano // tablice z wartosciami do sprawdzenia if (is_array($args[0])) { foreach ($args[0] as $arg) { // gwozdz programu! wywolujemy // rozpracowana funkcje i podajemy ewentualne // dodatkowe parametry if (self::$funcName['funkcja']($arg, $funcName['args']) == false) { return false; } } } // jezeli parametr nie jest tablica else { if (self::$funcName['funkcja']($args[0], $funcName['args']) == false) { return false; } } } // jezeli dolecialo az tutaj tzn., ze wartosc poprawnie zwalidowana return true; } // wylapie zle skonstruowany poczatek nazwy funkcji throw new Exception("Próba wywołania nierozpoznanej funkcji {$name}"); } /** * Szuka znanych sobie funkcji skladowych do wywolania. * @param string $name * @return array tablica z nazwa funkcji i parametrami */ protected static function extractFunction($name) { // calosc na male litery $name = strtolower($name); // jezeli zaczyna sie od 'not' if (stripos($name, 'not') === 0) { // ciachnij 'not' $name = substr($name, 3); // to co zostalo napisz z duzej litery $name = 'not' . ucfirst($name); return array( 'funkcja' => $name, 'args' => null); } // to samo jezeli zaczyna sie od 'is' elseif (stripos($name, 'is') === 0) { $name = substr($name, 2); $name = 'is' . ucfirst($name); return array( 'funkcja' => $name, 'args' => null); } elseif (stripos($name, 'gt') === 0) { return array( 'funkcja' => 'gt', // to co zostalo musi byc parametrem gt 'args' => substr($name, 2)); } elseif (stripos($name, 'eq') === 0) { return array( 'funkcja' => 'eq', 'args' => substr($name, 2)); } elseif (stripos($name, 'between') === 0) { $name = substr($name, 7); return array( 'funkcja' => 'between', // z tego co zostalo // rozwalamy wartosci przy 'and' 'args' => explode('and', $name)); } elseif (stripos($name, 'maxlength') === 0) { return array( 'funkcja' => 'maxLength', 'args' => substr($name, 9)); } // jezeli doszlo az tutaj to // nierozpoznano funkcji i // wywalam wyjatek else { throw new Exception("Nie rozpoznano funkcji {$name}"); } }
Skoro mamy szkielet do rozpoznawania funkcji to wrzucimy sobie trochę funkcji walidujących.
public static function isNull($var) { return is_null($var); } public static function notNull($var) { return !is_null($var); } public static function isEmpty($var) { return empty($var); } public static function notEmpty($var) { return !empty($var); } public static function isInt($var) { return is_int($var); } public static function isString($var) { return is_string($var); } /** * Sprawdza czy $var jest wieksze lub rowne $arg. * @param numeric $var * @param numeric $arg * @return bool */ public static function gt($var, $arg) { if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!"); if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba!"); return ($var > $arg); } /** * Sprawdza czy $var jest rowne $arg. * @param numeric $var * @param numeric $arg * @return bool */ public static function eq($var, $arg) { if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!"); if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba!"); return ($var == $arg); } /** * Sprawdza czy $var znajduje sie w przedziale $arg[0] <= $var <= arg[1]. * @param numeric $var * @param array $arg $arg[0] i $arg[1] typu numeric * @return bool */ public static function between($var, array $arg) { if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!"); if (!is_numeric($arg[0]) || !is_numeric($arg[1])) throw new Exception("Warunek {$arg[0]} lub {$arg[1]} nie jest liczba!"); return (($var >= $arg[0]) && ($var <= $arg[1])); } /** * Sprawdza max dlugosc ciagu $var. * @param string $var * @param int $arg * @return bool */ public static function maxLength($var, $arg) { if (!is_string($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest stringiem!"); if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba calkowita!"); return (strlen($var) <= (int) $arg); }
Skoro mamy „klocki”, z których możemy budować sobie warunki walidacji, poniżej kilka testów
if (Walidator::check_notempty_isint_gt5_between1and9($test)) { echo 'wartosc poprawna'; } else { echo 'BLAD!'; }
Dla wartości 6.5
funkcja zwróci błąd (isInt
), dla tablicy array(6,7,8,9)
wartość poprawną, z kolei Walidator::check_maxLength4(array('ala','miala','kota'))
zwróci również błąd, bo ‚miala’ ma 5 znaków