SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
Software Architect / Project Lead
Author of the Zend Framework 2.0 Cookbook International Conference Speaker Contributor to various Open Source Projects Freelance PHP Consultant
PHP Market Position, 11 Jan
2012 Used by high traffic sites Java ColdFusion Perl ASP.NET PHP Used by low traffic sites Used by fewer sites Used by many sites
Adopt now ● More stability
● Security ● Better engine (ie garbage collection) ● New language features ● Cleaner code because of more elegant ways of solving problems
PHP 5.4 ● Array short
syntax (javascript notation) ● Array dereferencing ● Class access on instantiation ● Indirect method call by array variable ● Engine processes OO code faster ● <?= ● JSONSerializable interface ● ...
ZF Use Case ZF Code
base used is for illustration purposes only and do –not-- express future possible implementations. ZF2.0 is not yet released so giving ZF3.0 implementations illustrates only my own assumptions. PHP5.4 stable is not yet released so no real world projects are and should be running this version. Because of this no real best practices have been defined.
namespace ZendView; class TemplatePathStack implements
TemplateResolver { public function setOptions($options = array()) { if (!is_array($options) && !$options instanceof Traversable) { throw new ExceptionInvalidArgumentException( __METHOD__ . ' expects an array or Traversable' ); } foreach ($options as $key => $value) { $this->setOption($key, $value); } return $this; } public function setOption($key, $value) { switch (strtolower($key)) { case 'lfi_protection': $this->setLfiProtection($value); break; case 'script_paths': $this->addPaths($value); break; default: break; } } }
namespace ZendMvcRouter; class RouteBroker implements
Broker { public function setOptions($options) { if (!is_array($options) && !$options instanceof Traversable) { throw new ExceptionInvalidArgumentException(sprintf( 'Expected an array or Traversable; received "%s"', (is_object($options) ? get_class($options) : gettype($options)) )); } foreach ($options as $key => $value) { switch (strtolower($key)) { case 'class_loader': // handle this case Default: break;// ignore unknown options } } return $this; } }
Problem: Code Duplication if (!is_array($options)
&& !$options instanceof Traversable) { throw new ExceptionInvalidArgumentException(sprintf( 'Expected an array or Traversable; received "%s"', (is_object($options) ? get_class($options) : gettype($options)) )); } foreach ($options as $key => $value) { //handle each case } return $this;
NOT an Option! A better
solution called Traits ● Would provide the setOptions in all classes that use the trait ● Eliminates the diamond problem
trait Options { public function
setOptions($options) { if (!is_array($options) && !$options instanceof Traversable) { throw new ExceptionInvalidArgumentException(sprintf( 'Expected an array or Traversable; received "%s"', (is_object($options) ? get_class($options) : gettype($options)) )); } foreach ($options as $key => $value) { $this->setOption($key, $value); } return $this; } }
namespace ZendView; class TemplatePathStack implements
TemplateResolver { use Options; public function setOption($key, $value) { switch (strtolower($key)) { case 'lfi_protection': $this->setLfiProtection($value); break; case 'script_paths': $this->addPaths($value); break; default: break; } } } $templateStack = new TemplatePathStack(); $templateStack->setOptions(['lfi_protection' => true]);
namespace ZendMvcRouter; class RouteBroker implements
Broker { use Options; public function setOption($key, $value) { switch (strtolower($key)) { case 'class_loader': // handle this case default: // ignore unknown options break; } } } $routeBroker = (new RouteBroker)->setOptions(['class_loader'=>'SomeLoader']);
namespace ZendLoader { use RuntimeException;
trait SplRegister { public function register() { spl_autoload_register(array($this, 'autoload')); } public function unregister() { spl_autoload_unregister(array($this, 'autoload')); } } class StandardAutoloader { use SplRegister; public function unregister() { throw new RuntimeException( 'you should not unregister the standard autoloader once registered' ); } } } namespace { $loader = new ZendLoaderStandardAutoloader(); $loader->register(); $loader->unregister(); // will throw the exception }
namespace ZendLoader { use RuntimeException;
class StandardAutoloader { public function unregister() { throw new RuntimeException( 'you should not unregister the standard autoloader once registered' ); } } } namespace NbeZfLoader { use ZendLoader as ZendLoader; class StandardAutoloader extends ZendLoaderStandardAutoloader { use ZendLoaderSplRegister; } } namespace { $loader = new NbeZfLoaderStandardAutoloader(); $loader->register(); //will register (trait) $loader->unregister(); // will unregister (trait) }
namespace ZendLoader { use RuntimeException;
class StandardAutoloader { public function unregister() { throw new RuntimeException( 'you should not unregister the standard autoloader once registered' ); } } } namespace NbeZfLoader { use ZendLoader as ZendLoader; class StandardAutoloader extends ZendLoaderStandardAutoloader { use ZendLoaderSplRegister { ZendLoaderStandardAutoloader::unregister insteadof ZendLoaderSplRegister; } } } namespace { $loader = new NbeZfLoaderStandardAutoloader(); $loader->register(); //will register (trait) $loader->unregister(); // will throw RuntimeException (base class) }
BUT Strict Standards: ZendFilterLocale and
ZendFilterSecondLocale define the same property ($locale) in the composition of ZendFilterAlpha. This might be incompatible, to improve maintainability consider using accessor methods in traits instead.
namespace ZendFilter { trait Locale
{ protected $locale = 'nl_BE'; public function getLocale() public function setLocale($locale = null) } trait SecondLocale { protected $locale = 'en_US'; public function setLocale($locale = null) } class Alpha { use Locale, SecondLocale { SecondLocale::setLocale insteadof Locale; } } } namespace { $alpha = new ZendFilterAlpha(); $alpha->setLocale('nl_BE'); }
namespace ZendView; class TemplatePathStack implements
TemplateResolver { use Options {Options::setOptions as protected} public function __construct($options = array()) { $this->setOptions($options); } } new TemplatePathStack(['lfi_protection' => true]);
namespace ZendView; trait Options {
public function setOptions($options) { //set the options } } interface TemplateResolver { public function setConfig($options); } class TemplatePathStack implements TemplateResolver { use Options {Options::setOptions as setConfig;} } (new TemplatePathStack)->setConfig(['lfi_protection' => true]);
namespace ZendView; trait Options {
public function setOptions($options) { } } class TemplatePathStack { use Options { Options::setOptions as setConfig; } } $templateStack = (new TemplatePathStack) ->setConfig(['lfi_protection' => true]); var_dump($templateStack instanceof Options); // false
namespace ZendView; trait Options {
abstract public function setOptions($options); } class TemplatePathStack { use Options; public function setOptions($options) { echo 'implementation enforced by trait'; } } $templateStack = (new TemplatePathStack) ->setOptions(['lfi_protection' => true]); var_dump($templateStack instanceof Options); // false
namespace ZendView; trait Options {
abstract public function setOptions($options); } class TemplatePathStack { use Options {Options::setOptions as setConfig;} public function setConfig($options) { echo 'implementation enforced by trait'; } } // Fatal error: Class ZendViewTemplatePathStack contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ZendViewTemplatePathStack::setOptions)
Magic Constants <?php trait Id
{ public function getClass() { echo __CLASS__; } public function getTrait() { echo __TRAIT__; } } class Foo { use Id; } (new Foo)->getClass(); //Foo (new Foo)->getTrait(); //Id
Good things about traits ●
Removes code duplication ● Helps keeping your code cleaner ● Maintainability ● Aliassing works for interfaces ● Property handling ● Easy Autoloading
Bad things about traits ●
Adds code complexity / understandability with the insteadof operator. ● Duck typing ● Aliassing Fails for Abstract Classes ● Property handling
Benchmarks 5.3 vs 5.4 ●
ZF project: http://nickbelhomme.com ● Benchmark / Profiling tool: xhprof ● How: 2 VirtualBox Machines - debian clones, with only PHP upgrade (5.4.0RC3)
5.3.3 ● Total Incl. Wall
Time (microsec): 674,842 ms ● Total Incl. CPU (microsecs): 672,042 ms ● Total Incl. MemUse (bytes): 13,827,864 bytes ● Total Incl. PeakMemUse (bytes): 13,865,976 bytes ● Number of Function Calls: 14,524
5.4.0RC3 Total Incl. Wall Time
(microsec): 166,813 ms ● Total Incl. CPU (microsecs): 168,011 ms ● Total Incl. MemUse (bytes):7,969,928 bytes ● Total Incl. PeakMemUse (bytes):8,015,944 bytes ● Number of Function Calls: 14,520
The End! THANK YOU Please
rate my talk https://joind.in/4774 contact@nickbelhomme.com Slideshare, Twitter, IRC: NickBelhomme http://blog.nickbelhomme.com