-
A new PHP version is about to be released. At the time I’m writing this blog PHP 5.5 is in beta 4.
Eager to see the updates, I’ve compiled the new beta version. The feature list is available at: http://www.php.net/manual/en/migration55.new-features.php
The generators are the most important feature..
Generating generators in PHP 5.5
A generator is basically a function that contains a call to “yield”.
Let’s take the example form php.net:
1<?php 2function xrange($start, $limit, $step = 1) { 3 for ($i = $start; $i <= $limit; $i += $step) { 4 yield $i; 5 } 6} 7 8echo 'Single digit odd numbers: '; 9 10/* Note that an array is never created or returned, 11* which saves memory. */ 12foreach (xrange(1, 9, 2) as $number) { 13 echo "$number "; 14} 15?>
Basically, the generator (xrange in this case), instead of returning an array, will return a value at a time, in order to be processed.
But wait… wasn’t this already possible before this version?
Generators before PHP 5.5
Before PHP 5.5 there were already Iterators:
1<?php 2 3class xrange implements Iterator 4{ 5 private $position = 0; 6 private $start; 7 private $limit; 8 private $step; 9 10 public function __construct($start, $limit, $step = 1) 11 { 12 $this->start = $start; 13 $this->limit = $limit; 14 $this->step = $step; 15 $this->position = 0; 16 } 17 18 function rewind() 19 { 20 $this->position = 0; 21 } 22 23 function current() 24 { 25 return $this->start + ($this->position * $this->step); 26 } 27 28 function key() 29 { 30 return $this->position; 31 } 32 33 function next() 34 { 35 ++$this->position; 36 } 37 38 function valid() 39 { 40 return $this->current() <= $this->limit; 41 } 42} 43 44echo 'Single digit odd numbers: '; 45 46/* Note that an array is never created or returned, 47 * which saves memory. */ 48foreach (new xrange(2, 9, 2) as $number) { 49 echo "$number "; 50} 51?>
Beside the fact that the Iterator is an object with multiple properties, basically we can achieve the same result.
But why do we need generators then? Simple! Instead of using ~40 lines of code, we can simply use 5 to achieve the same goal.
Another interesting thing is that:
1get_class(printer());
will return Generator.
Basically, a generator returns an object of type Generator, and this object extends Iterator.
The major difference, as it is described on the php.net website, is that the generator can not be reset, basically it goes one way only.
Sending information to the generators
Yes, generators work both ways, but each generator only works in one particular direction. If the syntax above is for “producing” data, then the syntax below is only for “consuming” data.
The syntax for a “consumer” is simple:
1<?php 2function printer() { 3 $counter = 0; 4 while(true) { 5 $counter++; 6 $value = yield; 7 echo $value . $counter . PHP_EOL; 8 } 9 echo ‘Never executed...' . PHP_EOL; 10} 11 12$printer = printer(); 13$printer->send('Hello!'); 14echo 'Something is happening over here...' . PHP_EOL; 15$printer->send('Hello!'); 16?>
The output will be:
1Hello!1 2Something is happening over here... 3Hello!2
Basically, the value of yield can be used as any other value. What’s interesting is the while. On php.net is the folowing comment:
// Sends the given value to the
// generator as the result of
// the yield expression and
// resumes execution of the
// generator.The loop is needed because the generator will stop after it processes the value and will only continue when a new value is received. If we remove the while, only the first value will be processed, regardless of how many times we’ll call send().
An interesting thing is that what comes after the loop will not be executed, that is in my case:
echo ‘Never executed…’ . PHP_EOL;So, if it looks like a good place to release a resource (e.g. DB or file), in fact it isn’t, because that code will never get executed.
It seems useful for logging. Again, nothing that couldn’t have been done before, but now it allows for an easier approach.
I’ve found though something that doesn’t work:
1<?php 2function printer() { 3 while(true) { 4 echo yield . PHP_EOL; 5 } 6} 7 8$printer = printer(); 9$printer->send('Hello world!'); 10 11foreach($printer as $line) { 12 echo $line . PHP_EOF; 13}
A little chaotic, isn’t it? But I was wondering what would happen:
Fatal error: Uncaught exception ‘Exception’ with message ‘Cannot rewind a generator that was already run’ in…So, once send() is used on an iterator, you can’t use it as an iterator again. Of course, another one can be generated with:
printer();What is more confusing is that Generator is a final class, so it can’t be extended, and if you try to instantiate it directly (although even if it worked it would be useless):
Catchable fatal error: The “Generator” class is reserved for internal use and cannot be manually instantiated in…Conclusion
It is an interesting feature because it simplifies things a lot when you try to create an iterator.
Also the use of send() seems very interesting, not because it is doing something new, but because it is doing it easier.
On the other hand, I don’t like that there is the same syntax for both generator versions and even more that what is after the while is not getting executed. I think the syntax is a little confusing because there isn’t a clear difference between the two. On the other hand, this already exists in Python, so for inspirator the examples from this language can be used.
-
The notion of closure in PHP, even though it appeared in PHP 5.3, as I’ve said before on my blog, it was properly done only in 5.4.
Wikipedia tells us:
In computer science, a closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment—a table storing a reference to each of the non-local variables (also called free variables) of that function.
In PHP this isn’t a very popular concept or very well-known. It is often mistaken for Anonymous Functions. But in functional programming languages it is very popular, because they really need it!
Scheme
When Brendan Eich designed JavaScript, relied on the Scheme language and ended up doing an implementation of this language with a C syntax. The C syntax was and is a lot more popular, and back then (1995) the Java programming language was very “fashionable”.
The Scheme syntax is similar to Lisp, in the sens that is using parenthesis abound expressions in order to execute them. The operators are defined as functions and just like them, there must be placed left of the parenthesis.
Let’s take an Scheme closure example:
1(define (make-counter) 2 (let ((count (begin 3 (display "run parent function and return 0") 4 ))) 5 (lambda () 6 (set! count (+ count 1)) 7 (begin 8 (display "inside child function ") 9 count))))
The function is setting a “count” variable, with the value 0 and displays “run parent function and return 0”, then returns another lambda function, that is incrementing the variable defined in the main function and then displays “inside child function”.
I’m storing the resulting function in a variable in order to later run it multiple times:
1> (define counter (make-counter)) 2run parent function and return 0 3> (counter) 4inside child function 1 5> (counter) 6inside child function 2
In other words, each time I’m calling (make-counter), it will return a new function that has access to the environment at the time at which it was created. If it looks strange because of the syntax, I promise that it will fell a lot more natural in JavaScript.
This concept is very interesting for encapsulation. The environment from the time when the parent function was been executed can be encapsulated, and later it can be used without worrying that it was changed by external causes.
For the functional programming languages this is a very interesting concept. Yet when it comes to object orientated languages, the concept seems almost useless, because objects also have the purpose of encapsulation.
JavaScript
From the beginning JavaScript was a hybrid, a functional programming language, object orientated, with prototype based inheritance. And if this wasn’t enough, the syntax was taken from Java (C).
JavaScript didn’t inherited a lot from Scheme, but it did inherit the closure concept.
A reason why there was a need for closures in Scheme is that that if a function is not finding a variable in its environment, it will search for it in its container’s environment. Let’s take an example:
1(define x 1) 2(define (add-in-env y) (+ x y))
If we call add-in-env with 2:
1(add-in-env 2) -> 3
It looks just as ambiguous as in JavaScript, but is not exactly like that. In Scheme to do mutation is not that easy, simple and transparent, so an subsequent operation of:
1(define x 2)
will result in an error.
In JavaScript resulted a hybrid. Mutation is permitted, but the notion of searching a variable in the current environment remained:
1var x = 1; 2var add_in_env = function (y) { 3 return x + y; 4} 5 6add_in_env(2); // returns 3
Up to this point is ok, but for:
1x = 2; 2add_in_env(2); // returns 4
For this case, things can get out of hand very easy:
But, in order to solve the issue, we can just define a variable in the environment that will finish execution (will close):
1var make_counter = function () { 2 console.log("run parent function and set counter to 0") 3 var count = 0; 4 5 return function () { 6 count = count + 1; 7 console.log("inside child function"); 8 return count; 9 } 10} 11 12var counter = make_counter(); 13console.log(counter()); 14console.log(counter()); 15 16var counter2 = make_counter(); 17console.log(counter2()); 18console.log(counter()); 19console.log(counter2());
The output will be:
1run parent function and set counter to 0 2inside child function 31 4inside child function 52 6run parent function and set counter to 0 7inside child function 81 9inside child function 103 11inside child function 122
Even though the main function finished executing, the environment inside it is kept as a closure for the function that was returned. Only when there aren’t any more references to the sub-function the memory allocated for the closure will also be deallocated.
Even though JavaScript has objects, it doesn’t have private methods. An approach is to add a “_” (underscore) in front of the function name and consider it private. From my point is like asking the developers that will later use the code to consider this function private. Of course this is not very consistent.
Let’s take an example:
1var obj = { 2 _secretFunction : function (key) { console.log(‘do secret ’ + key) }, 3 doStuff : function (key) { this._secretFunction(key) } 4} 5 6obj.doStuff(‘stuff’); // do secret stuff
It seems that there is a public method “doStuff” and a private one “_secretFunction”. Nevertheless you can not prevent a user from calling “_secretFunction” or even worse, to modify it:
1obj._secretFunction = function (key) { console.log('new secret ' + key); } 2 3obj.doStuff('stuff'); // new secret stuff
If we want to hide the function, and make this obvious for everybody, again, we can use closures:
1var obj = (function () { 2 var secretFunction = function (key) { console.log(‘do secret ’ + key) } 3 4 return { 5 doStuff : function (key) { 6 secretFunction(key) 7 } 8 } 9})(); 10 11obj.doStuff(‘stuff’); // do secret stuff
Because the parent function was not stored but rather immediately executed, basically the space in which secretFunction was defined has already finished its execution, encapsulating the logic. The object returned can call the function because it was defined in the same environment as the object.
Looks complicated at first, but is really very easy when you understand the concept.
And then it was… PHP
PHP includes a lot of different options. It was originally developed as a Perl framework, later the engine was rewritten in C.
PHP is a dynamic language that includes a lot of concepts, from objects, interfaces and anonymous functions, up to goto labels. The development direction for the language is not very clear, it rather offers the possibility for different approaches.
In the weird PHP history, somewhere in version 4, syntax for Anonymous Functions was added, but only in PHP 5.3 a more “normal” version appeared.
Also in version 5.3 the first closure version was introduced:
1$scalar = 5; 2 3$closure = function () use ($scalar) { 4 return 'Scalar: ' . $scalar . PHP_EOL; 5}; 6 7echo $closure(); // Scalar: 5 8 9$scalar = 7; 10 11echo $closure(); // Scalar: 5
This version mostly worked, but you had to specify what you want to send to the closure.
And there were other inconveniences:
1<?php 2class Foo { 3 private function privateMethod() { 4 return 'Inside private method'; 5 } 6 7 public function bar() { 8 $obj = $this; 9 return function () use ($obj) { 10 return $obj->privateMethod(); 11 }; 12 } 13} 14 15$obj = new Foo(); 16$closure = $obj->bar(); 17echo $closure(); 18 19Fatal error: Call to private method Foo::privateMethod() from context '' in [...][...] on line 10
Is not working because you can not send $this as a parameter to a closure, and if you try the above trick you still can’t access the private methods. Remember, this was happening in PHP 5.3.
The idea to introduce a closure of this kind seems strange to me. But this is not the first time something “strange” is introduced in PHP, as I was saying before about the Anonymous Functions. Sometimes is looking like work in progress.
I think everybody was expecting a more JavaScript like closures. I think that JavaScript had a big influence in making this concept so popular.
In version PHP 5.4 things changed, we finally have a closure as we would expect:
1class Foo { 2 private function privateMethod() { 3 return 'Inside private method'; 4 } 5 6 public function bar() { 7 return function () { 8 return $this->privateMethod(); 9 }; 10 } 11} 12 13$obj = new Foo(); 14$closure = $obj->bar(); 15echo $closure(); // Inside private method
And it works!
You can even do:
1unset($obj); 2echo $closure();
and it will work, because the object in which the closure was defined remains in memory until either the script finishes execution, or a call like this is made:
1unset($closure);
For more details on how closures work in PHP 5.4, check out this post.
-
Over an year ago, I started working on the Magento platform. In last year’s spring, a colleague from Optaros took the Magento Developer Plus certification exam. Since then, I began to like the idea of taking the certification exam, more as a motivation to learn the ins and outs of Magento.
Few months ago I was enrolled into a company study group for the certification. This was the first time I was sponsored for a certification (yes, until now everything was with my money). Preparing in a study group was a whole different experience.
Those who have more experience in a field balance the situation for the others and can give better examples from their own experience. It’s easier to understand from concrete examples then to try to imagine the scenarios yourself.
The certification is available through Prometric. So when you decide that you’re ready you can go to the website to purchase the voucher and schedule the exam.
The price for a voucher is 260$, not exactly cheap, but if you get to convince your boss to pay, it probably won’t be so bad. 🙂
But let’s get to the more interesting subject, the preparation.
Materials
Magento is not doing very good on this subject, there are very few materials and they are not centralized.My sources were:
– Magento® Certified Developer Plus Exam Study Guide – it is compulsive to read the guide and try to find answers to all the questions in it;
– Magento training – especially Fundamentals of Magento Development
– blogs – I don’t want to give any names, there are a lot of people that write about the problems that they encounter and blog about the exam.Unfortunately there isn’t a way like for PHP, ZF and Symfony where you can find all you need in one place, basically it depends on your luck and searching skills, there isn’t an “official version”. Things become weird when you find different approaches that are version specific.
How did I prepare
I began with the video training. It’s not perfect by it’s very helpful. I think the problem with most certifications is that you don’t get to work with all the available modules, just like in PHP you don’t get to work that much with sockets and streams.Even though you don’t get the code and sometimes it is hard to follow and transcribe the examples, I think that the video tutorials are one of the most important sources at the moment.
Secondly, with the Study Guide in my hand, I began to try to answer the questions from it. When I joined the Study Group, the work divided between all the members in the group. My advantage was that it was the second generation of the group and we could profit from the documentation already developed by the first group.
If you’re preparing by yourself, I think the most important thing is to start, that’s the hardest part. And if you don’t know where to start, Google search the Magento questions, there are already a lot of people that are posting the explanations.
Answers for the questions from the first chapters are the easiest to find. As the number of the chapter is getting bigger, the number of Google results decreases.
But after the first questions, you should understand what is all about and in theory you will no longer need the documentation.
Use Mage::log(Varien_Debug::backtrace(true, false)); for stack trace and xdebug (http://xdebug.org/) to see what’s going on behind the scene. With patience, all the questions find their answers.
Because it was a group, the study was easier for me, but even so, to be sure of the explanation I has to dive deep in the code.
The exam
Some of the questions are difficult, but there are also accessible ones. The questions in the exam are off all levels of difficulty.For Plus, the exam takes 2h not 2.5h as it is specified in the guide.
If you opted for Plus, there are 11 questions from Enterprise and advanced difficulty questions, of which 7 correct ones are required to pass. Basically this is the difficulty difference. For this questions it matters how much Enterprise experience you have.
In the guide for each exam, the questions are broken in percentages for each chapter.
Because in the non Plus certification there are no Enterprise questions, you only have to answer the necessary percentage from the full exam in order to pass and it’s not required to have a certain percentage from a certain chapter.
Things that are done regularly are analyzed in detail, it is important to understand how each function that is approached in each chapter works and what is the purpose of all those tags in the xml files.
Usually there are things you work with, or at least with which there is a good probability you have been working from the modules listed in the guide.
Post exam
Before you leave the room you’ll know if you’ve passed or not. When you exit the room you’ll receive a printed paper with the correct number of questions from each section from the total number .In case you haven’t been successful you’ll receive by mail from Magento a voucher with a discount for a future attempt. They state that you should study at least 3 more weeks before you try again. Anyway, after you’ve taken the exam you’ll have a better view over your overall knowledge for a future attempt.
After few days (3 in my case) you will be able to see your profile on the Magento website as a reference.
The diploma got to Romania in about a month, the delivery address is the one from the Magento website account.
Best of luck!
-
Another year has passed without native unicode support for PHP. Yes, PHP6 is not here yet, in case anybody was still asking…
But, the version that is now here is PHP 5.4. With this version only refinements were added, there weren’t changes as big as there were on PHP 5.3. In PHP 5.4, the big addition are “traits” and, my favorite, the new version for closure.
As the keywords for last year were Drupal and Magento, this year the keyword was only Magento.
A couple of months ago, more or less forced by the circumstances, I’ve taken the Magento Plus certification exam. For this certification, Optaros, my employer, had a major influence. We had been more or less made to take the exam and we also had to be part of a company level study group.
I haven’t been part of a study group since faculty, and I must admit that I’ve forgotten how useful it is. Colleagues with more Magento experience (unlike me who I’ve been working with Magento for a little more than an year), had helped a lot to clarify issues and to document them.
But more about this in another blog, that will follow shortly (I hope)…
Anyway, after studying Magento in so much detail, I must admit that I have a lot more respect for the platform. After you analyze the backend architecture, a different picture is emerging. The architecture is very interesting and quite flexible, which makes you overlook some of it’s shortcomings.
Now that a new year has begun, I wish I’m going to publish more, I think in the last period I haven’t been very “productive” when it comes to publishing, either text or code.
Also this year I want to take at least another certification exam. As the Magento certification was set only for this year, I still have a lot of options on my plate.
That’s about all for 2012 and plans for 2013.
I wish you an excellent 2013!
-
Sometimes we need to overwrite an observer. The first way that usually comes in mind is overwriting the model. Usually is named Observer.php, because this is the “best practice”.
And NO, you don’t have to overwrite the model. Observer.php doesn’t extend anything anyway and usually contains all of the module’s observers, so you can’t overwrite the same observer in more than one module.
How it works?
In magento when a new observer is added, it must have an unique identifier. This identifier is the key!Actually, there is another element: “area”. When Mage::dispatchEvent(…) is performed, events will be dispatched using “area” and “identifier”.
For example, the admin notification system, which is observing “controller_action_predispatch”, will run:
1=> "global"(area) 2=> "controller_action_predispatch"(event) 3=> "adminnotification"(identifier)
then:
1=> "adminhtml"(area) 2=> "controller_action_predispatch"(event) 3=> "adminnotification"(identifier)
If the event was in the frontend area, it would be: “global” then “frontend”.
Overwriting
Overwriting is in fact a observer defined in the same config area as the original event (global, frontend or adminhtml), attached to the same event and with the same identifier as the original observer (e.g. adminnotification).Let’s say we have to overwrite “adminnotification”. This observer is in Mage/AdminNotification. The unique identifier is defined in etc/config.xml:
1... 2 <adminhtml> 3... 4 <events> 5 <controller_action_predispatch> 6 <observers> 7 <adminnotification> 8 <class>adminnotification/observer</class> 9 <method>preDispatch</method> 10 </adminnotification> 11 </observers> 12 </controller_action_predispatch> 13 </events> 14... 15 </adminhtml> 16...
From the example above we can see:
– area: adminhtml
– event: controller_action_predispatch
– identifier: adminnotificationThe module activation file will be: app/etc/modules/CP_AdminNotification.xml
1<?xml version="1.0"?> 2<config> 3 <modules> 4 <CP_AdminNotification> 5 <active>true</active> 6 <codePool>local</codePool> 7 <depends> 8 <Mage_AdminNotification/> 9 </depends> 10 </CP_AdminNotification> 11 </modules> 12</config>
I’ve added dependencies because without the original module, this module will be useless.
There’s a “best practice” to name a module that is overwritten with the same name as the original module.
The configuration file for this module, will contain practically everything you’ll need for the overwriting: area, event and identifier. The file is located in app/code/local/CP/AdminNotification/etc/config.xml:
1<?xml version="1.0"?> 2<config> 3 <modules> 4 <CP_AdminNotification> 5 <version>0.0.1</version> 6 </CP_AdminNotification> 7 </modules> 8 <global> 9 <models> 10 <cp_adminnotification> 11 <class>CP_AdminNotification_Model</class> 12 </cp_adminnotification> 13 </models> 14 </global> 15 <adminhtml> 16 <events> 17 <controller_action_predispatch> 18 <observers> 19 <adminnotification> 20 <class>cp_adminnotification/observer</class> 21 <method>overwrittenPreDispatch</method> 22 </adminnotification> 23 </observers> 24 </controller_action_predispatch> 25 </events> 26 </adminhtml> 27</config>
The observer should contain all the new logic. The file is in app/code/local/CP/AdminNotification/Model/Observer.php, just like you would probably expect from the structure above.
1<?php 2 3class CP_AdminNotification_Model_Observer { 4 5 public function overwrittenPreDispatch(Varien_Event_Observer $observer) { 6 // noua logica din observer 7 } 8}
Disabling
Disabling is preaty similar to overwriting, the difference is in the config and the fact that an observer file is not needed anymore, because there isn’t a new logic.The new config.xml file is:
1<?xml version="1.0"?> 2<config> 3... 4 <adminhtml> 5 <events> 6 <controller_action_predispatch> 7 <observers> 8 <adminnotification> 9 <type>disabled</type> 10 </adminnotification> 11 </observers> 12 </controller_action_predispatch> 13 </events> 14 </adminhtml> 15</config>