Claudiu Persoiu

Blog-ul lui Claudiu Persoiu


Archive for 25 February 2012

Magento native stack trace

with 5 comments

Exista momente cand ai nevoie sa vezi stack trace-ul, sa stii cum ai ajuns pana la un anumit punct. PHP are doua functii native pentru a realiza acest lucru: debug_backtrace() si debug_print_backtrace. Prima intoarce un array iar a doua afisaza stacktrace-ul pe ecran.

Problema in sine este ca acestea trebuie customizate pentru Magento, pentru ca este foarte posibil cand rulezi debug_backtrace() sa ramai fara memorie inainte sa poti trimite rezultatul catre un fisier de log.

Magento are o functie nativa pentru acest lucru: Varien_Debug::backtrace([bool $return = false], [bool $html = true], [bool $withArgs = true]). Pentru a trimite catre log stacktrace-ul se apeleaza pur si siplu:

Mage::log(Varien_Debug::backtrace(true, false));

Aceasta tehnica este foarte utila in momentul in care vrei sa vezi de unde se initializeaza anumite obiecte si ce metode se ruleaza pana in acel moment.

Written by Claudiu Persoiu

25 February 2012 at 11:48 AM

Posted in Magento,PHP

Tagged with , , ,

PHP 5.4 – Closures asa cum ar trebui!

with 5 comments

Notiunea de Closure, a fost introdusa in PHP 5.3, o data cu o noua sintaxa, “mai traditionala” pentru functiile anonime.

PHP 5.3

In 5.3, un closure se baza pe termenul “use”, care transmite anumite variabile functiei anonime, transformand-o intr-un closure.

Problema este ca functia anonima nu va avea acces decat la variabilele trimise folosind “use”. In cazul obiectelor ele sunt trimise prin referinta, dar in cazul variabilelor scalare (int, string, etc.) acestea se transmit prin valoare, asa cum face implicit in PHP 5+:

$scalar = 5;

$closure = function () use ($scalar) {
     return 'Scalar: ' . $scalar . PHP_EOL;
};

echo $closure(); // Scalar: 5

$scalar = 7;

echo $closure(); // Scalar: 5

O alta problema este ca nu se pot trimite $this in cadrul obiectelor, deci doar proprietatile sau metodele care sunt publice nu pot fi accesate de closure.

PHP 5.4

In PHP 5.4 folosirea cuvantului “use” este optionala, iar tot mediul in care functia anonima a fost creata este disponibil in interiorul functiei.

Avantajul este ca atunci cand functia anonima este generata in interiorul unei alte functii, sau a unei metode, functia anonima va putea accesa mediul in care aceasta a fost creata chiar si dupa terminarea executiei acestuia. Obiectele din mediul creat se vor dezaloca de abea dupa ce se ultima referinta catre closure se va sterge:

class testClass {

        private $changeableVar = 1;
        private $bigVar;

        public function __construct() {
                // Allocate a big variable so we can see the changes in memory
                $this->bigVar = str_repeat("BigWord", 5000);
        }

        /**
         * O metoda care intoarce un closure
         */
        public function closure() {

                return function () {
                        // Display the value of a private property of the object
                        echo 'Private property: ' . $this->changeableVar.PHP_EOL;

                        // Change the value of a private property of the object
                        $this->changeableVar = 2;
                };
        }

        /**
         * O metoda care afisaza o variabila privata
         */
        public function showChangeableVar() {
                echo 'Private property in method: ' . $this->changeableVar.PHP_EOL;
        }

}

// Memoria inainte sa fie alocat obiectul
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 229896

// Creare obiect
$testObj = new testClass();

// Creare closure
$closure = $testObj->closure();

// Executie closure
$closure(); // Private property: 1

// Afisare valoare curenta a proprietatii private
$testObj->showChangeableVar(); // Private property in method: 2

// Memoria inainte sa fie desalocat obiectul
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266240

// Dezalocare obiect
unset($testObj);

// Memoria dupa ce a fost dezalocat obiectul, nu este o diferenta mare in memorie
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266152

// Executie closure dupa ce obiectul in care a fost creata a fost dezalocat
echo $closure(); // Private property: 2

// Dezalocat closure si o data cu el mediul in care a fost generat
unset($closure);

// Memoria dupa ce a fost stearsa ultima referinta catre obiect
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 230416

Callable type hinting

Inca un nou lucru introdus legat de closures introdus in PHP 5.4 este un nou “type hint”: “callable”. De fapt “callable” se refera la orice functie anonima, chiar si la un nou mod de a apela o metoda a unui obiect:

<?php
// O functie care foloseste type hinting
function typeHinting(callable $a) {
     echo $a() . PHP_EOL;
}

// Un closure
$closure = function () {
     return __FUNCTION__;
};

// Apelare functie cu type hinting cu un closure ca argument
typeHinting($closure); // {closure}

class testClass {
     public function testMethod() {
          return __METHOD__;
     }
}

// Un obiect de test
$testObj = new testClass();

// Noua forma de apelare a unei metode dintr-un obiect
$objCallable = array($testObj, 'testMethod');

// Apelare functie type hinting cu noua forma de apelare ca argument
typeHinting($objCallable); // testClass::testMethod

Cred ca de abea acum este momentul sa spunem ca PHP suporta closures cu adevarat!

Written by Claudiu Persoiu

11 February 2012 at 5:10 PM

Posted in PHP

Tagged with , , , ,

Magento dead end – Breadcrumbs

without comments

Intr-una din aventurile mele prin codul Magento, m-am lovit de urmatoarea problema: trebuia sa adaug un link la breadcrumb.

Cum documentatia nu e foarte bogata, dupa putin debug-ing (nu foarte mult), am ajuns in core la Mage_Page_Block_Html_Breadcrumbs.

Metoda este foarte auto-explicativa: addCrumb($crumbName, $crumbInfo, $after = false). Daca tot eram acolo am zis sa arunc un ochi in ea:

function addCrumb($crumbName, $crumbInfo, $after = false)
{
  $this->_prepareArray($crumbInfo, array('label', 'title', 'link', 'first', 'last', 'readonly'));
  if ((!isset($this->_crumbs[$crumbName])) || (!$this->_crumbs[$crumbName]['readonly'])) {
    $this->_crumbs[$crumbName] = $crumbInfo;
  }
  return $this;
}

Ce este interesant este parametul $after, dupa cum se poate observa, desi are chiar si o valoare default, nu se foloseste nicaieri. In rest functia functioneaza asa cum este de asteptat, probabil de asta nu se plange lumea atat de des.

Written by Claudiu Persoiu

3 February 2012 at 10:03 PM

Posted in Magento,PHP

Tagged with ,