A minap eszembe jutott, hogy milyen jó is lenne, ha a Sublime jelezné, ha van valami elgépelés az éppen szerkesztett fájlba. És bár létezik elég sok megoldás a problémára, ami ráadásul még több nyelvet is (Python, CSS, JavaScript, stb.) támogat, de azért mégis csak sokkal mókásabb egy sajátot írni.

A megoldás lényege, hogy valahol a vinyón van egy PHP bináris, amit megfuttatunk a -l kapcsolóval, ami nem futtatja a fájlt, hanem csak szintaxisra ellenőriz. A válasz a PHP szokásos "parse error" szövege lesz, ami azt írja ki, hogy hol hasalt el a fordító, ami nem feltétlen esik egybe azzal, hogy hol van a hiba. A kódot többféleképpen meg lehetne valósítani (pl. parancsként, amit menüből, vagy billentyűkombinációra lehet futtatni), én azt választottam, hogy mentés eseményre automatikusan fusson le, ha megfelelő a fájl kiterjesztése:

import sublime, sublime_plugin, os, subprocess, re

class PhpLintEventListener(sublime_plugin.EventListener):
    key = "php_lint_syntax_error"
    
    def on_post_save(self, view):
        if not view.settings().has("php_lint"):
            return
        
        config = view.settings().get("php_lint")
        
        bin_path = config.get("binary", "")
        name, ext = os.path.splitext(view.file_name())
        
        if not bin_path or ext not in config.get("extensions", []):
            return
        
        view.erase_regions(self.key)
        view.erase_status(self.key)
        
        shell = sublime.platform() == "windows"
        p = subprocess.Popen([bin_path, "-l",  view.file_name()], shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = p.communicate()
        
        if "" == stderr:
            data = stdout
        else:
            data = stderr
        
        result = re.match(r"(.+?) in (.+?) on line ([0-9]+).*", data, re.M | re.S)
        if result:
            error = result.group(1)
            line = result.group(3)
            
            view.add_regions(self.key, [view.full_line(view.text_point(int(line) - 1, 0))], "markup.deleted", "dot")
            view.set_status(self.key, error + " on line " + line)

Nem egy bonyolult jószág, ha létezik a config és a fájl kiterjesztése benne van a configban megadott listában, akkor megfuttatjuk a PHP binárist és megkeressük a kimenetében, hogy hányadik sorban volt a hiba. A hibás sort kiemeljük és a hiba szövegét a státuszba ki is írjuk. A szükséges config pedig valahogy így néz ki:

"php_lint" : {
    "binary" : "d:\\php\\5.2\\php.exe",
    "extensions" : [".php"]
}

Ezt lehet pakolni a Preferences > Settings - User részbe vagy akár a projekt beállításai közé is (a .sublime-project fájlon belül a "settings" blokkba).

Több, mint 5 és fél év után elérkezett az idő, hogy nyugdíjba vonuljon a régi oldal és megszülessen az 5.0-s verzió. Mivel egyébként nagyjából 8 év magasságában járunk, elég nagy bizonyossággal állíthatom, hogy ilyen sokáig még egy design se bírta. Sok mindent nem is tudnék hozzátenni, az eredmény jól látható (ha csak nem rss olvasóban nézi a kedves olvasó a bejegyzést). Néhány dolog, ami változott:

  • A modern kor elvárásaihoz némiképp igazodva az oldal valamivel reszponzívabb lett.
  • A kommentelési lehetőség kikerült, a továbbiakban a bejegyzéshez kapcsolódó Google+ postban lehet majd megjegyezni dolgokat.
  • Like/+1 gombok sincsenek, csak hogy letisztultabbak és egyszerűbbek legyünk.
  • Bár még mindig nem vittem túlzásba a tartalmat, de már nem csak "Folyamatban..." van az Archívum oldalon. :)

Ééés nagyjából ennyi... Nem vittem túlzásba. :) Aztán biztos maradt egy rakat hiba és hiányosság benne, amit majd az elkövetkezendő évek során bőven lesz időm javítani.

Szóval, már egy ideje foglalkoztat a mobil fejlesztés. Annak is főleg a zöld robotos ágazata. Gondoltam ideje lenne valami maradandóbbat alkotni a gépen heverő sok teszt projektnél, úgyhogy bele is vágtam egy listás alkalmazás elkészítésébe, annak ellenére, hogy listás alkalmazásokkal Dunát lehetne rekeszteni (vagy ha már itt tartunk, lassan már bármilyen típusú alkalmazásokkal... :)). A végeredmény (vagy inkább az első verzió) megtekinthető a Google Play-en:

Vagy mobilosoknak egy kényelmesebb market alkalmazás linken:

Amit tud:

  • Listákat kezelni! :)
  • Külső alkalmazás segítségével QR kódot beolvasni és azt elmenteni listaelemként az egyszerű és gyors felvitel érdekében.
  • Ha linket kap listaelemnek, azt feldolgozza és a meta adatokkal együtt jeleníti meg (a Facebook-os Open Graph tagek hozzák igazán lázba, mással nem nagyon foglalkozik :)).
  • Megosztani egy listát (pl. e-mailben elküldeni).

Nagyjából ennyi, nem egy bonyolult jószág. Az elkészítésében az ActionBarSherlock volt a segítségemre, ami remekül valósítja meg a 4.0-s Action Bar-t 4.0 előtti készülékeken is. Kellemes listázást. :)

Most, hogy már van egy virtuális szerverünk, kellene kezdeni vele valami mókás dolgot. Lehetne mondjuk egy távolról is vezérelhető build rendszerünk (a "távolról" mondjuk ebben az esetben talán egy kicsit túlzás :)), amit a kedvenc szövegszerkesztőnk automatikusan tudna vezérelni. Az úgy kellőképp mókásan hangzik ahhoz, hogy belevágjunk. :)

Ahhoz, hogy legyen értelme a build rendszernek, nem árt, ha van mit build-elni. Tegyük fel mondjuk a példa kedvéért, hogy CSS helyett szeretnénk Sass-t, JavaScript helyett pedig CoffeeScript-et használni. Természetesen a rendszer képességei nem merülnek ki ennyiben, lehetne mondjuk olyat is csinálni, hogy a sablon fájlokat fordítsa le PHP-ra, vagy a konfigurációs XML-ekből gyártson tömböket, esetleg minden unit tesztet lefuttasson. A lehetőségek száma, ahogy mondani szokás, végtelen, de maradjunk az eredeti kettőnél, a többi a kedves olvasó fantáziájára van bízva. Kezdjük is rögtön a telepítéssel:

Sass

sudo apt-get install ruby rubygems
sudo gem install sass

A Sass [Syntactically Awesome Stylesheets] nevezetű előfeldolgozó néhány hasznos kiegészítéssel segít ráncba szedni az elvadult CSS kóddzsungelt.

CoffeeScript

sudo apt-get install nodejs npm
sudo npm install coffee-script

A CoffeeScript a funkcionális programozási nyelvekre és talán egy csöppet a Ruby-ra emlékeztető nyelv a JavaScript egy komolyabb újragondolása (a Sass-CSS viszonylathoz képest), de mentségére legyen mondva, hogy egy az egyben valid JavaScript-re fordul.

Építkezzünk

A build-elésben segítségünkre lesz a vicces nevű PHP-s build eszköz, a Phing. A következő módon érhetjük el, hogy feltelepüljön:

sudo apt-get install php-pear
sudo pear channel-discover pear.phing.info
sudo pear install phing/phing

A példához a következő minimális projekt könyvtárszerkezetet fogjuk használni:

  • assets/
    • coffee/
    • sass/
  • www/
    • css/
    • js/
  • build.xml

Az assets/ könyvtárban vannak a nyers fájlok, a www/ könytárba mennek a generált fájlok, amiket nem árt kívülről is elérni. A kulcs pedig a build.xml, ami a Phing számára tartalmaz utasításokat. Kezdetnek valami ilyesmi például megteszi:

<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" default="assets">
    <property name="sass_dir" value="${project.basedir}/assets/sass/" />
    <property name="coffee_dir" value="${project.basedir}/assets/coffee/" />
    
    <property name="css_target" value="${project.basedir}/www/css/" />
    <property name="js_target" value="${project.basedir}/www/js/" />
    
    <target name="sass">
        <exec command="sass --no-cache --update &quot;${sass_dir}:${css_target}&quot;" />
    </target>
    
    <target name="coffee">
        <exec command="coffee -o &quot;${js_target}&quot; &quot;${coffee_dir}&quot;" />
    </target>
    
    <target name="assets">
        <phingcall target="sass" />
        <phingcall target="coffee" />
    </target>
</project>

A projekt könyvtárában (egy szinten a build.xml-lel) állva ki tudjuk adni a következő három parancsot, amivel a Sass-t, CoffeeScript-et és mindkettőt egyszerre lefordíthatjuk (ha nem adunk meg semmit a phing után, akkor a default assets fog lefutni):

phing sass
phing coffee
phing assets

Az alkalmazás

Már csak azt kellene elérni, hogy a fájlok módosítása után a megfelelő parancs automatikusan lefusson. Bár mind a Sass, mind a CoffeeScript rendelkezik megoldással a problémára (--watch), a későbbiekre is gondolva inkább valami általánosabb megoldásra lenne szükség. Mondjuk egy webes minialkalmazás, ami a kapott paraméterek függvényében meghívja a megfelelő parancsot. A kódszerkesztő alkalmazásunk pedig ezt a paraméterezett URL-t hívogathatná. Mondjuk valami ilyesmit:

http://builder.vbox/index.php?project=projektneve&target=target

Az a bizonyos index.php pedig valami ilyen kis egyszerű dolog lenne (az egyszerűség ára az, hogy élünk azzal a feltételezéssel, hogy az egyes projektek a /var/www/projektneve.vbox/ könyvtárban vannak és eltekintünk az olyan dolgoktól, mint például a target valódiságának az ellenőrzése):

$dir = '/var/www/' . get('project') . '.vbox/';
if (!file_exists($dir . 'build.xml')) {
    exit('invalid_project');
}

$target = get('target');
if (!$target) {
    exit('no_target');
}

chdir($dir);
shell_exec('phing ' . escapeshellcmd($target));
exit('ok');

function get($name) {
    if (empty($_GET[$name])) {
        return '';
    }
    return preg_replace('/[^a-z0-9\-\.]/i', '', $_GET[$name]);
}

A plugin

Ezzel meg is van a távolról is vezérelhető egyszerű kis build rendszerünk. A kedvenc szerkesztőnkhöz írhatunk egy plugin-t, ami mentésre meghívja a megfelelő URL-t, hogy legenerálódjanak a CSS/JS fájlok (vagy akár tetszőleges billentyűkombinációra tetszőleges build parancsot meghívhatunk). Sublime Text 2 esetén valahogy így nézne ki a dolog:

import sublime, sublime_plugin
import urllib, urllib2
import os, threading

class BuilderThread(threading.Thread):
    def __init__(self, project, target):
        threading.Thread.__init__(self)
        self.project = project
        self.target = target
    def run(self):
        try:
            data = urllib.urlencode({
                'project': self.project,
                'target': self.target,
            })
            request = urllib2.Request('http://builder.vbox/index.php?' + data)
            response = urllib2.urlopen(request).read()
            return
        except (urllib2.HTTPError) as (e):
            err = '%s: HTTP error %s contacting API' % (__name__, str(e.code))
        except (urllib2.URLError) as (e):
            err = '%s: URL error %s contacting API' % (__name__, str(e.reason)) 
        
        sublime.error_message(err)

class BuilderEventListener(sublime_plugin.EventListener):
    def __init__(self):
        sublime_plugin.EventListener.__init__(self)
    
    def on_post_save(self, view):
        name, ext = os.path.splitext(view.file_name())
        project = view.settings().get('builder_project_name', False)
        
        if (False == project):
            return
        
        if (ext == '.coffee'):
            BuilderThread(project, 'coffee').start()
        elif (ext == '.scss' or ext == '.sass'):
            BuilderThread(project, 'sass').start()

A plugin használ egy builder_project_name nevű beállítást, amit az éppen aktuális projekt .sublime-project fájljában érdemes megadni:

{
    "settings": {
        "builder_project_name": "test-project"
    }
}

Ezzel meg is volnánk, kellemes építkezést.

Épp a sorozatos oldal második verziójának fejlesztésébe készülök komolyabban belevágni. Ennek kapcsán eszembe jutott, hogy milyen jó bejegyzést lehetne ebből kanyarítani. Mármint abból, hogy milyen módjai vannak a kényelmes otthoni projekt fejlesztésnek.

Összepiszkíthatnánk például a jelenlegi operációs rendszerünket mindenféle web- és egyéb szerverekkel, de ez nem egy szép megoldás. Telepíthetnénk egy extra operációs rendszert egy külön partícióra, de az, hogy a jelenlegiből ki kell lépni, oda pedig be... esélytelenné teszi a fejlesztést egy kellően lusta ember számára (én :)). A legjobb lenne egy külön gép, amit hálózaton keresztül elérünk. Ennek a legköltséghatékonyabb változata a virtuális gép, így ezen a vonalon fogunk tovább haladni. Hozzávalók egy személyre:

Pro tipp: az Ubuntu szerver iso-ját ne a VirtualBox telepítése közben töltsük le, mert a VirtualBox telepítés közben hajlamos időlegesen megkavarni az internet kapcsolatot és jól meg fog szakadni a letöltés.

Telepítés

A letöltések és a szokásos next-next-finish telepítés befejeztével hozzáadhatunk egy új Linux / Ubuntu típusú virtuális gépet és egy új virtuális merevlemezt a varázsló segítségével. Még mielőtt elindítanánk, a Settings / Shared Folders részben érdemes hozzáadni egy könyvtárat a saját gépünkről, amiben a projekteket fogjuk tárolni, hogy ne kelljen később Samba-t telepíteni. Az Auto-mount részt ne pipáljuk be, azt később kézzel beállítjuk majd. A Settings / Network részbe se árthat benézni és az Adapter 1-et ízlés szerint megpiszkálgatni. Nálam a Bridged Adapter volt a nyerő az Attached to részben. A VirtualBox elég okos és az első indításnál felajánlja, hogy etessünk meg a géppel egy CD-t. Ajánlatos itt beadagolni a korábban letöltött Ubuntu szerver iso-ját, mert az nagyban megkönnyíti a telepítést. :)

Az Ubuntu nem egy bonyolult jószág, így valószínűleg a telepítéssel se lesznek problémák. Amíg fut, tetszés szerint lehet fogyasztani a bespájzolt hideg élelmet illetve sört. Hogy, hogy nem előbb-utóbb eljutunk egy ilyen képernyőhöz:

Itt a LAMP server-t az Apache-PHP-MySQL szentháromság miatt erősen ajánlott bepipálni, mert valószínűleg szükségünk lesz rá. Én telepíteni szoktam OpenSSH server-t is, mert már annyira hozzászoktam a PuTTy használatához. :)
Ha ezzel megvagyunk, az első belépés után rögtön érdemes is nyomni egy frissítést:

sudo apt-get update
sudo apt-get upgrade

Valamint telepíteni a VirtualBox Guest csomagját a jobb támogatás érdekében:

sudo apt-get install virtualbox-guest-utils

A projekt könyvtárak beállítása

A fejlesztés a /var/www/ könyvtárban fog történni a virtuális gép nézőpontjából. Hogy kényelmes legyen, érdemes ezt kivezetni valahova a gazda gép merevlemezére. Ezért állítottuk be korábban a Shared Folders részt. A művelet elvégzéséhez a következő sorokat kell felvenni az /etc/fstab fájl végére (na jó, a komment nem kötelező :)):

# VirtualBox Shared Folder
projects /var/www vboxsf auto,rw,uid=1000,gid=33 0 0

A projects helyére a Shared Folder felvitelénél megadott nevet kell írni. Az uid=1000 a rendszer telepítése során létrehozott felhasználó, a gid=33 a www-data csoport. A módszernek az az előnye is megvan a Samba-féle megoldással szemben, hogy nem kell futnia a virtuális gépnek ahhoz, hogy a fájlokat módosítani tudjuk. Az uid és gid értékeként megadható számok után az /etc/passwd és /etc/group fájlokban lehet érdeklődni.

Szerver elérés

Ha minden jól ment, az ifconfig eth0 által kidobott ip címen el tudjuk érni a gépet. Ha nem, akkor a VirtualBox beállítások Network részénél érdemes a lehetőségeket végigpróbálgatni, hogy melyik jön be (ahány hálózat, annyi beállítás).
Az egyszerűséget szem előtt tartva érdemes valami egyedi, egyébként nem létező domain-el felruházni a gépet, hogy ne ip címeket kelljen mindig írogatni. Nálam a *.vbox domain-ek vannak erre fenntartva. A legegyszerűbb, ha a hosts fájlba felvesszük őket (Windows: c:\Windows\System32\drivers\etc\hosts, Linux: /etc/hosts), pl.:

192.168.1.117 default.vbox
192.168.1.117 projektneve.vbox
192.168.1.117 subdomain.projektneve.vbox

Apache, PHP, MySQL beállítás

Az egyes projektek a /var/www/projektneve.vbox/ könyvtárban kapnak helyet. Az alap Apache confignak csinálunk egy default.vbox nevet/könyvtárat:

mkdir /var/www/default.vbox
sudo mcedit /etc/apache2/sites-available/default

A megnyíló fájlban a DocmentRoot és a Directory résznél szereplő /var/www/ után kell még egy default.vbox/-ot írni. Aztán pedig

sudo service apache2 reload

A /etc/apache2/httpd.conf-ba esetleg még érdemes egy ServerName default.vbox sort beledobni és újraindítani az Apache-ot, hogy megszűnjön a "Could not reliably determine the server's fully qualified domain name" hibaüzenet.

A projekt VirtualHost beállításai a /etc/apache2/sites-available/projektneve.conf fájlba kerülnek. Egy egyszerű példa, hogy nagyjából mit is tartalmaz egy ilyen:

<VirtualHost *:80>
    ServerName projektneve.vbox
    ServerAlias www.projektneve.vbox

    DocumentRoot /var/www/projektneve.vbox/www
    <Directory />
        Options FollowSymLinks
        AllowOverride All
    </Directory>
    <Directory /var/www/projektneve.vbox/www/>
        Options FollowSymLinks
        AllowOverride All
    </Directory>

    ErrorLog /var/www/projektneve.vbox/log/apache_www_error.log
    CustomLog /var/www/projektneve.vbox/log/apache_www_access.log combined

    LogLevel warn
</VirtualHost>

A kész site beállításokat a következő parancsokkal tudjuk engedélyezni:

sudo a2ensite projektneve.conf
sudo service apache2 reload

A MySQL-en nincs sok beállítani való, telepítéskor elkérte a root felhasználójához az új jelszót, mást meg nem nagyon kell piszkálni. A vizuálisabb típusoknak esetleg egy phpmyadmin telepítése még nem árthat:

sudo apt-get install phpmyadmin

Ha kértük, a csomagból telepítés során be is köti magát az Apache-ba a /etc/apache2/conf.d/phpmyadmin.conf segítségével és a http://ipcím/phpmyadmin/ címen el is érhető az oldal. Ehelyett, ha kedvünk tartja létrehozhatunk neki egy saját VirtualHost-ot is akár.

A PHP beállításánál érdemes arra törekedni, hogy minél jobban hasonlítson az éles rendszerre, így ezzel kapcsolatban nem sokat tudok mondani.

Első körben ennyi, kellemes telepítgetést. :)

Érdekes módon a deadlime kedvenc kódszerkesztő alkalmazása a Sublime. Egyrészt azért, mert a többszörös kijelölés az bizony hihetetlenül fantasztikus egy találmány. Másrészt pedig Python-ban lehet hozzá plugin-eket írni.

Kedves kollégám említette a minap, hogy egyik régebben használt szerkesztőjében volt valamiféle funkció, amivel a vágólap korábbi tartalmait lehetett újra felhasználni. Aztán elkezdtem gondolkodni rajta, hogy vajon lehetne-e egy ilyen plugin-t írni Sublime-hoz. Aztán megírtam. :)

Ha már így alakult, ragadjuk meg az alkalmat és nézzük meg kicsit, hogyan is néz ki egy Sublime plugin. A funkció meglepően kevés kódból megoldható: először is felül kell csapnunk a beépített copy és cut utasításokat sajáttal úgy, hogy megmaradjon az eredeti funkcionalitás is, de közbe mentsük egy tömbbe az adatokat.

class ClipboardHistoryCopyCommand(sublimeplugin.TextCommand):
    def run(self, view, args):
        saveSelections(view)
        view.runCommand('copy');

Egy kis XML-lel meg is mondjuk a proginak, hogy a mi parancsunkat használja a Ctrl+C nyomkodása esetén:

<bindings>
    <binding key="ctrl+c" command="clipboardHistoryCopy" />
</bindings>

A cut nem túl meglepő módon elég hasonlóan néz ki (csak a beépített cut parancsot hívjuk meg a végén). A saveSelections végzi a munka javát. Végigmegy az összes kijelölésen és amelyik nem üres, azt elpakolja egy tömbbe, aminél még arra is figyelünk, hogy ne lehessen túl nagy:

clipboardMaxSize = 100
clipboardData = []

def saveSelections(view):
    for region in view.sel():
        if region.begin() != region.end():
            clipboardData.insert(0, view.substr(region))
            if len(clipboardData) > clipboardMaxSize:
                clipboardData.pop()

Annyi maradt már csak, hogy valami kellően kézreálló billentyűkombinációra meg is jelenítse az előzményeket és tudjunk belőle kedvünkre válogatni. Legnagyobb szerencsénkre tudjuk használni a beépített lista ablakot, amiben még kereső is van (ugyanaz, ami a Ctrl+P vagy a Ctrl+R kombinációkra is bejön):

class ClipboardHistoryPasteCommand(sublimeplugin.TextCommand):
    def pasteSelected(self, view, index):
        for region in view.sel():
            view.insert(region.begin(), clipboardData[index])
    
    def run(self, view, args):
        view.window().showSelectPanel(
            clipboardData,
            functools.partial(self.pasteSelected, view),
            None,
            sublime.SELECT_PANEL_MONOSPACE_FONT
        );

És természetesen a hozzá tartozó kis XML részlet:

<binding key="alt+shift+q" command="clipboardHistoryPaste" />

Nem a legtökéletesebb megoldás, például plugin újratöltéseknél elveszik a clipboardData tömb tartalma (lehetne például fájlba menteni menet közben), de kezdetnek megteszi. A teljes csomagot innen le lehet rántani (érdekes módon ClipboardHistory.sublime-package fájlnévvel nem mentek volna a billentyűparancs felüldefiniálások, mivel az Sublime ABC sorrendben tölti be a plugineket és a Default később van... :)).

[a képet köszönjük ShutterBugChef-nek]

Bár nem tegnap történt, hogy az 5.3-as sorozat első verziója kijött, gondoltam kicsit körbejárom a névtelen függvények témakörét az ősidőktől napjainking. Az ősidő alatt itt természetesen a 4-es verziót értem, amikor még csak a call_user_func állt a rendelkezésünkre. Lássuk, hogyan is ment ez.

A create_function módszer (attól tekintsünk el, hogy a __FUNCTION__ varázskonstans csak a 4.3-as verzióban jelent meg):

$f = create_function('', 'echo __FUNCTION__ . "\n";');
call_user_func($f);

A függvény neve stringként módszer:

$f = 'myFunction';
call_user_func($f);

Az osztály és a statikus metódus neve tömbként:

$f = array('MyClass', 'myStaticFunction');
call_user_func($f);

Az objektum és a metódus neve tömbként:

$c = new MyClass();
$f = array($c, 'myFunction');
call_user_func($f);

Az osztály és a statikus metódus neve stringként (5.2.3-as PHP-tól):

$f = 'MyClass::myStaticFunction';
call_user_func($f);

Az objektum meghívása (5.3.0-s PHP-tól):

$c = new MyClass();
call_user_func($c);

És ezzel el is érkeztünk a jelenhez. Az 5.3.0-s verzióval megjelentek a closure-ök (az újfajta névtelen függvények), amolyan JavaScript-es definiálással:

$f = function () {
};

Természetesen a teljes visszafelé kompatibilitásról ne is álmodjunk ezért kezdjük is el végignézni az előző módokat, hogy mi működik továbbra is:

A create_function módszer megy továbbra is (emlékeim szerint 5.3 előtt is működött így, ezért ez nem túl meglepő):

$f = create_function('', 'echo __FUNCTION__ . "\n";');
$f();

A függvény neve stringként módszer (működik):

$f = 'myFunction';
$f();

Itt sajnos meg is állhatunk. A tömbös rendszerek (PHP Fatal error: Function name must be a string) és az osztály+statikus metódus neve stringként (PHP Fatal error: Call to undefined function MyClass::myStaticFunction()) nem működik.

Maradt még az objektum direkt meghívása, ami működik, de ez sem túl nagy meglepetés, mivel az 5.3.0-s verzióbal vezették be hozzá az új varázsmetódust:

$c = new MyClass();
$c();

Ilyenkor (és a call_user_func-os esetben is) az osztály __invoke() metódusa hívódik meg.

Ezzel azt hiszem nagyjából ki is veséztük a különböző callback típusok és névtelen függvények hívhatóságát. Maradt még némi scope kérdés, de az házi feladat (annyit megsúgok, hogy a use a kulcsszó). Egy kis segítség hozzá:

Az úgy volt, hogy elgondolkoztam azon, hogy vajon miért jó az, ha a kiszolgálás folyamatát több részre bontják. Ha egyáltalán jó az. Offline, bolti kiszolgálásról van szó, mielőtt bárki - a blog témáját figyelembe véve - jogosan másra gondolna.

Ha vesszük az értékesítő-pénztáros-árukiadó modellt, érzésre úgy tűnik, hogy a több sor végigjárása miatt többet is várunk. De a sorbanállás pszichológiája fura egy dolog. Jó példa erre a hipermarket, ahol N pénztárnak van N sora azért, mert az N pénztár 1 sor felállás zavaró lehet az embereknek a hosszú sor miatt, holott a várakozási idő úgy kevesebb lenne.

Tovább...

Úgy tűnik tartom magamat az elmúlt években már megszokott kontent mennyiséghez. Most is csak azért írok, hogy hírt adjak arról, hogy összedobtam egy kis oldalt, aminek segítségével nyomon lehet követni ismerőseink és saját magunk sorozatnézési szokásait. Használjátok egészséggel. :)

Ja... a cím: s01e01.hu