SlideShare a Scribd company logo
MASTERING NAMESPACES! Nick Belhomme January 29, 2011 – PHPBenelux Conference
About Me @NickBelhomme Freelance PHP Consultant  International Conference Speaker  Zend Framework 2.0 Cookbook Author  Contributor to various Open Source Projects  ZCE  ZFCE
Passions Life Traveling People Sharing Ideas Networking
Dreams A world of unbounded potential. Where everybody believes they can Be, do and have whatever they think about. Think your idea Act upon your idea Refine later
BACK TO NAMESPACES <----
Why Other big programming languages support them Introduced in PHP 5.3 – One and a half years ago Modern Next Gen Frameworks (Symfony 2.0, Zend Framework 2.0 and others) Job market demands it Use it or loose it
What are they? Abstract container created to hold a logical grouping of unique identifiers. Unique identifiers are names. (in practice: classes, functions, constants) Each identifier is associated with the namespace where it is defined.
PEAR Naming Convention  R.I.P. No more clever workaround for lack of namespace support No more very long function and class names
Welcome Readability new Zend_Layout_Controller_Action_Helper_Layout() new Layout() class NbeZf_Model_User extends Nbe_Model_Abstract class User extends AbstractModel
How to create the container space <?php namespace Nbe\Collection; <?php declare(encoding='UTF-8'); namespace Nbe\Collection; Per file <?php /** * @namespace */ namespace Nbe\Collection;
How to create the container space <?php namespace Nbe\Model; const LIBRARY_PATH = '/www/libs/Nbe'; class AbstractModel { /* ... */ } function draw() { /* ... */  } namespace NbeZf; const LIBRARY_PATH = '/www/libs/NbeZf'; class AbstractModel { /* ... */ } function sayHello() { /* ... */  } Mixing spaces per file <?php namespace Nbe\Model { const LIBRARY_PATH = '/www/libs/Nbe'; class AbstractModel { /* ... */ } function draw() { /* ... */  } } namespace { const APP_PATH = '/www/libs/NbeZf'; function __autoload() { /* ... */  } }
Common Mistakes <?php namespace \Nbe; // rest of code Fatal error: Undefined constant 'Nbe' <?php namespace Nbe; class Interface {} <?php namespace Nbe; class Abstract {} Parse error: syntax error, unexpected T_INTERFACE Parse error: syntax error, unexpected T_ABSTRACT
Different name types Fully Qualified Name \Nbe\Model\AbstractModel Qualified Name Model\AbstractModel Unqualified Name AbstractModel
Autoloading namespaces function __autoload($class) { require_once str_replace( '\\',  DIRECTORY_SEPARATOR,  $class ) . '.php'; } new \NbeZf\Model\User() maps to NbeZf\Model\User require_once /NbeZf/Model/User.php
Autoloading namespaces <?php namespace Nbe\Loader; function autoLoader($className) { require_once \str_replace('\\', \DIRECTORY_SEPARATOR, $className) . '.php'; } <?php require 'Nbe/Loader/autoloader.php'; spl_autoload_register('Nbe\\Loader\\autoloader'); $user = new Nbe\Entity\User();
Resolving namespace calls <?php namespace Nbe; class Model {} $model = new Model(); echo get_class($model); Output: Nbe\Model <?php namespace Nbe; function model() { return __FUNCTION__; } echo model(); Output: Nbe\model
Consequences <?php namespace Nbe; $collection = new ArrayObject(); Fatal error: Class 'Nbe\ArrayObject' not found <?php namespace Nbe; $collection = new \ArrayObject(); Indicate global namespace with a single backslash <----
Function fallbacks <?php namespace Nbe; var_dump(explode(';', ' some;cool;words ')); <?php namespace Nbe; \var_dump( \ explode(';', 'some;cool;words')); Better practice. Explicitly call global space FULLY QUALIFIED NAMES Compile time <---- Runtime and potential  happy debugging feature <----
Constants fallbacks <?php namespace { const APP = 'test'; } namespace Nbe { const E_ERROR = 10; echo APP; echo E_ERROR; } Better practice. Explicitly call global space Fully quaylified names, compile time <?php namespace { const APP = 'test'; } namespace Nbe { const E_ERROR = 10; echo \APP; echo E_ERROR; } Runtime and potential  happy debugging feature
Magic constants beware <?php namespace Nbe; echo __LINE__; echo __FILE__; echo __DIR__; echo __FUNCTION__; echo __CLASS__; echo __METHOD__; echo __NAMESPACE__; Magic constants cannot be overwritten so no global namespace prefix is allowed
Namespaces are per file <?php function sayHello() { echo 'hello'; } <?php namespace Nbe; require '/utils.php'; \sayHello();
But what about using other namespaces? Fully Qualified namespace calling is still tedious.  So how do we solve this? ?
Importing to the rescue! <?php namespace DancingQueen\Entity; use NbeZf\Entity\AbstractEntity, Zend\Validator\StaticValidator; class User extends AbstractEntity { public function setId($id) { If (!StaticValidator::execute($id, 'digits')) { throw new InvalidArgumentException('User id needs to be numeric'); } ... } }
OOOH Noes a naming collision :((( <?php namespace NbeZf\Validator; use Zend\Validator\StaticValidator; class StaticValidator extends StaticValidator  { public static function getBroker() { if (null === self::$broker) { static::setBroker(new ValidatorBroker()); } return self::$broker; } } Fatal error: Cannot declare class  NbeZf\Validator\StaticValidator  because the name is already in use
Aliasing to the rescue! <?php namespace NbeZf\Validator; use Zend\Validator\StaticValidator as ZfStaticValidator; class StaticValidator extends ZfStaticValidator  { public static function getBroker() { if (null === self::$broker) { static::setBroker(new ValidatorBroker()); } return self::$broker; } }
Aliasing is in-explicitly used <?php namespace DancingQueen\Entity; use NbeZf\Entity\AbstractEntity as AbstractEntity, Zend\Validator\StaticValidator as StaticValidator; class User extends AbstractEntity { public function setId($id) { If (!StaticValidator::execute($id, 'digits')) { throw new InvalidArgumentException('User id needs to be numeric'); } ... } }
Dynamic Loading <?php namespace Nbe; $class = 'ArrayObject'; $object = new $class(); echo get_class($object); Output: ArrayObject Always Absolute Path
Dynamic Loading from other namespace <?php namespace Nbe; $class = '\Zend\View\PhpRenderer'; $object = new $class(); echo get_class($object); Ouput: Zend\View\PhpRenderer Fully qualified names
Dynamic Loading from current <?php namespace Nbe; $class = __NAMESPACE__ . '\\' .  'ArrayObject'; $object = new $class(); echo get_class($object); Output: Nbe\ArrayObject
Resolution Rules  <?php namespace Nbe; use Tata\Nbe; $object = new ArrayObject(); <?php namespace Nbe; use Tata\Nbe; $object = new Nbe\ArrayObject(); Resolves to Nbe\ArrayObject Resolves to Tata\Nbe\ArrayObject
Resolution Rules for Dummies When an alias is available – and there is always an alias available when importing - all unqualified and qualified names are translated using the current import rules. When no alias is available all unqualified and qualified names have the current namespace prepended. Constants and functions have fallbacks to global namespace for unqualified names.
Explicitly Loading from current <?php namespace Nbe; class Exception extends \Exception{} ?> <?php namespace Nbe; use Exception; const ERROR_INFO = 10; try { try { if (1===1) { throw new Exception('instantiates \Exception'); } } catch (\Exception $e) { throw new namespace\Exception('instantiates \Nbe\Exception', ERROR_INFO, $e); } } catch (namespace\Exception $e) { echo 'error: '.$e->getMessage(); echo PHP_EOL; echo 'nested exception error: '.$e->getPrevious()->getMessage(); } File 1 File 2 namespace keyword
Coming to an end, but first some Timeline changes PHP4 class constructor has the same name as the class > PHP5 class constructor is  __construct but accepts PHP4 convention >5.3 namespaces are introduced, nothing changes >= 5.3.3 Backward compatibility change. Only __construct is now regarded as the constructor for namespaced code.
And some cool resources The PHP manual  http://www.php.net/namespaces Ralph Schindlers namespace convert tool https://github.com/ralphschindler/PHPTools Plus comments on it by Cal Evan http://blog.calevans.com/2010/03/27/zends-new-namespace-converter/ Google: php namespaces http://www.google.be/search?q=php+namespaces Zend Framework 2.0 Cookbook http://blog.nickbelhomme.com/php/zend-framework-2-0-cookbook_324
And we reached the end, Any questions?
The End! THANK YOU [email_address] Slideshare, Twitter, IRC: NickBelhomme http://blog.nickbelhomme.com

More Related Content

PDF
PHP traits, treat or threat?
PDF
Laravel 4 package development
PPTX
Zephir - A Wind of Change for writing PHP extensions
PPTX
PHP 7 Crash Course - php[world] 2015
PDF
Last train to php 7
PDF
Nginx pres
PDF
Fighting Fear-Driven-Development With PHPUnit
PDF
Continuous Quality Assurance
PHP traits, treat or threat?
Laravel 4 package development
Zephir - A Wind of Change for writing PHP extensions
PHP 7 Crash Course - php[world] 2015
Last train to php 7
Nginx pres
Fighting Fear-Driven-Development With PHPUnit
Continuous Quality Assurance

What's hot (20)

PDF
Diving into HHVM Extensions (PHPNW Conference 2015)
PDF
Get your teeth into Plack
PDF
PECL Picks - Extensions to make your life better
PPT
PDF
DevOps in PHP environment
PDF
CLI, the other SAPI
PDF
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
PDF
Modern PHP
PDF
PHP7 is coming
PDF
Spl in the wild
ODP
The why and how of moving to php 5.4
PDF
How to deploy node to production
ODP
Caching and tuning fun for high scalability @ FrOSCon 2011
PDF
Introduction to PHP
PPT
PPT
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
PDF
PPTX
Doctrine 2.0 Enterprise Persistence Layer for PHP
PPTX
PHP from soup to nuts Course Deck
Diving into HHVM Extensions (PHPNW Conference 2015)
Get your teeth into Plack
PECL Picks - Extensions to make your life better
DevOps in PHP environment
CLI, the other SAPI
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Modern PHP
PHP7 is coming
Spl in the wild
The why and how of moving to php 5.4
How to deploy node to production
Caching and tuning fun for high scalability @ FrOSCon 2011
Introduction to PHP
ZFConf 2012: Dependency Management в PHP и Zend Framework 2 (Кирилл Чебунин)
Doctrine 2.0 Enterprise Persistence Layer for PHP
PHP from soup to nuts Course Deck
Ad

Similar to Mastering Namespaces in PHP (20)

PDF
Using PHP 5.3 Namespaces for Fame and Fortune
ODP
What's new, what's hot in PHP 5.3
ODP
Namespace inPHP
PDF
Advanced PHP Simplified - Sunshine PHP 2018
PDF
Advanced PHP Simplified
ODP
PHP 5.3 And PHP 6 A Look Ahead
PDF
Composer Helpdesk
PDF
PHP 5.3 Overview
PDF
Zend Framework 2 Patterns
PPT
Php Docs
ODP
Best practices tekx
PPTX
Php Extensions for Dummies
PPTX
FFW Gabrovo PMG - PHP OOP Part 3
PPT
Writing Friendly libraries for CodeIgniter
PPTX
PHP 5.3
PDF
Introduction to PHP 5.3
PDF
Php7 extensions workshop
PDF
Let's Talk Scope
PPT
PHPBootcamp - Zend Framework
Using PHP 5.3 Namespaces for Fame and Fortune
What's new, what's hot in PHP 5.3
Namespace inPHP
Advanced PHP Simplified - Sunshine PHP 2018
Advanced PHP Simplified
PHP 5.3 And PHP 6 A Look Ahead
Composer Helpdesk
PHP 5.3 Overview
Zend Framework 2 Patterns
Php Docs
Best practices tekx
Php Extensions for Dummies
FFW Gabrovo PMG - PHP OOP Part 3
Writing Friendly libraries for CodeIgniter
PHP 5.3
Introduction to PHP 5.3
Php7 extensions workshop
Let's Talk Scope
PHPBootcamp - Zend Framework
Ad

More from Nick Belhomme (6)

ODP
Vagrant move over, here is Docker
ODP
Mastering selenium for automated acceptance tests
ODP
PHP Quality Assurance Workshop PHPBenelux
PDF
Cursus phpunit
PDF
Zend Framework Form: Mastering Decorators
PDF
Zend Framework 1.8 workshop
Vagrant move over, here is Docker
Mastering selenium for automated acceptance tests
PHP Quality Assurance Workshop PHPBenelux
Cursus phpunit
Zend Framework Form: Mastering Decorators
Zend Framework 1.8 workshop

Recently uploaded (20)

PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Empathic Computing: Creating Shared Understanding
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
sap open course for s4hana steps from ECC to s4
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Machine learning based COVID-19 study performance prediction
PDF
Approach and Philosophy of On baking technology
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Big Data Technologies - Introduction.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Review of recent advances in non-invasive hemoglobin estimation
Empathic Computing: Creating Shared Understanding
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm
20250228 LYD VKU AI Blended-Learning.pptx
sap open course for s4hana steps from ECC to s4
Understanding_Digital_Forensics_Presentation.pptx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Machine learning based COVID-19 study performance prediction
Approach and Philosophy of On baking technology
NewMind AI Weekly Chronicles - August'25 Week I
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Big Data Technologies - Introduction.pptx
MYSQL Presentation for SQL database connectivity
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Advanced methodologies resolving dimensionality complications for autism neur...

Mastering Namespaces in PHP

  • 1. MASTERING NAMESPACES! Nick Belhomme January 29, 2011 – PHPBenelux Conference
  • 2. About Me @NickBelhomme Freelance PHP Consultant International Conference Speaker Zend Framework 2.0 Cookbook Author Contributor to various Open Source Projects ZCE ZFCE
  • 3. Passions Life Traveling People Sharing Ideas Networking
  • 4. Dreams A world of unbounded potential. Where everybody believes they can Be, do and have whatever they think about. Think your idea Act upon your idea Refine later
  • 6. Why Other big programming languages support them Introduced in PHP 5.3 – One and a half years ago Modern Next Gen Frameworks (Symfony 2.0, Zend Framework 2.0 and others) Job market demands it Use it or loose it
  • 7. What are they? Abstract container created to hold a logical grouping of unique identifiers. Unique identifiers are names. (in practice: classes, functions, constants) Each identifier is associated with the namespace where it is defined.
  • 8. PEAR Naming Convention R.I.P. No more clever workaround for lack of namespace support No more very long function and class names
  • 9. Welcome Readability new Zend_Layout_Controller_Action_Helper_Layout() new Layout() class NbeZf_Model_User extends Nbe_Model_Abstract class User extends AbstractModel
  • 10. How to create the container space <?php namespace Nbe\Collection; <?php declare(encoding='UTF-8'); namespace Nbe\Collection; Per file <?php /** * @namespace */ namespace Nbe\Collection;
  • 11. How to create the container space <?php namespace Nbe\Model; const LIBRARY_PATH = '/www/libs/Nbe'; class AbstractModel { /* ... */ } function draw() { /* ... */ } namespace NbeZf; const LIBRARY_PATH = '/www/libs/NbeZf'; class AbstractModel { /* ... */ } function sayHello() { /* ... */ } Mixing spaces per file <?php namespace Nbe\Model { const LIBRARY_PATH = '/www/libs/Nbe'; class AbstractModel { /* ... */ } function draw() { /* ... */ } } namespace { const APP_PATH = '/www/libs/NbeZf'; function __autoload() { /* ... */ } }
  • 12. Common Mistakes <?php namespace \Nbe; // rest of code Fatal error: Undefined constant 'Nbe' <?php namespace Nbe; class Interface {} <?php namespace Nbe; class Abstract {} Parse error: syntax error, unexpected T_INTERFACE Parse error: syntax error, unexpected T_ABSTRACT
  • 13. Different name types Fully Qualified Name \Nbe\Model\AbstractModel Qualified Name Model\AbstractModel Unqualified Name AbstractModel
  • 14. Autoloading namespaces function __autoload($class) { require_once str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php'; } new \NbeZf\Model\User() maps to NbeZf\Model\User require_once /NbeZf/Model/User.php
  • 15. Autoloading namespaces <?php namespace Nbe\Loader; function autoLoader($className) { require_once \str_replace('\\', \DIRECTORY_SEPARATOR, $className) . '.php'; } <?php require 'Nbe/Loader/autoloader.php'; spl_autoload_register('Nbe\\Loader\\autoloader'); $user = new Nbe\Entity\User();
  • 16. Resolving namespace calls <?php namespace Nbe; class Model {} $model = new Model(); echo get_class($model); Output: Nbe\Model <?php namespace Nbe; function model() { return __FUNCTION__; } echo model(); Output: Nbe\model
  • 17. Consequences <?php namespace Nbe; $collection = new ArrayObject(); Fatal error: Class 'Nbe\ArrayObject' not found <?php namespace Nbe; $collection = new \ArrayObject(); Indicate global namespace with a single backslash <----
  • 18. Function fallbacks <?php namespace Nbe; var_dump(explode(';', ' some;cool;words ')); <?php namespace Nbe; \var_dump( \ explode(';', 'some;cool;words')); Better practice. Explicitly call global space FULLY QUALIFIED NAMES Compile time <---- Runtime and potential happy debugging feature <----
  • 19. Constants fallbacks <?php namespace { const APP = 'test'; } namespace Nbe { const E_ERROR = 10; echo APP; echo E_ERROR; } Better practice. Explicitly call global space Fully quaylified names, compile time <?php namespace { const APP = 'test'; } namespace Nbe { const E_ERROR = 10; echo \APP; echo E_ERROR; } Runtime and potential happy debugging feature
  • 20. Magic constants beware <?php namespace Nbe; echo __LINE__; echo __FILE__; echo __DIR__; echo __FUNCTION__; echo __CLASS__; echo __METHOD__; echo __NAMESPACE__; Magic constants cannot be overwritten so no global namespace prefix is allowed
  • 21. Namespaces are per file <?php function sayHello() { echo 'hello'; } <?php namespace Nbe; require '/utils.php'; \sayHello();
  • 22. But what about using other namespaces? Fully Qualified namespace calling is still tedious. So how do we solve this? ?
  • 23. Importing to the rescue! <?php namespace DancingQueen\Entity; use NbeZf\Entity\AbstractEntity, Zend\Validator\StaticValidator; class User extends AbstractEntity { public function setId($id) { If (!StaticValidator::execute($id, 'digits')) { throw new InvalidArgumentException('User id needs to be numeric'); } ... } }
  • 24. OOOH Noes a naming collision :((( <?php namespace NbeZf\Validator; use Zend\Validator\StaticValidator; class StaticValidator extends StaticValidator { public static function getBroker() { if (null === self::$broker) { static::setBroker(new ValidatorBroker()); } return self::$broker; } } Fatal error: Cannot declare class NbeZf\Validator\StaticValidator because the name is already in use
  • 25. Aliasing to the rescue! <?php namespace NbeZf\Validator; use Zend\Validator\StaticValidator as ZfStaticValidator; class StaticValidator extends ZfStaticValidator { public static function getBroker() { if (null === self::$broker) { static::setBroker(new ValidatorBroker()); } return self::$broker; } }
  • 26. Aliasing is in-explicitly used <?php namespace DancingQueen\Entity; use NbeZf\Entity\AbstractEntity as AbstractEntity, Zend\Validator\StaticValidator as StaticValidator; class User extends AbstractEntity { public function setId($id) { If (!StaticValidator::execute($id, 'digits')) { throw new InvalidArgumentException('User id needs to be numeric'); } ... } }
  • 27. Dynamic Loading <?php namespace Nbe; $class = 'ArrayObject'; $object = new $class(); echo get_class($object); Output: ArrayObject Always Absolute Path
  • 28. Dynamic Loading from other namespace <?php namespace Nbe; $class = '\Zend\View\PhpRenderer'; $object = new $class(); echo get_class($object); Ouput: Zend\View\PhpRenderer Fully qualified names
  • 29. Dynamic Loading from current <?php namespace Nbe; $class = __NAMESPACE__ . '\\' . 'ArrayObject'; $object = new $class(); echo get_class($object); Output: Nbe\ArrayObject
  • 30. Resolution Rules <?php namespace Nbe; use Tata\Nbe; $object = new ArrayObject(); <?php namespace Nbe; use Tata\Nbe; $object = new Nbe\ArrayObject(); Resolves to Nbe\ArrayObject Resolves to Tata\Nbe\ArrayObject
  • 31. Resolution Rules for Dummies When an alias is available – and there is always an alias available when importing - all unqualified and qualified names are translated using the current import rules. When no alias is available all unqualified and qualified names have the current namespace prepended. Constants and functions have fallbacks to global namespace for unqualified names.
  • 32. Explicitly Loading from current <?php namespace Nbe; class Exception extends \Exception{} ?> <?php namespace Nbe; use Exception; const ERROR_INFO = 10; try { try { if (1===1) { throw new Exception('instantiates \Exception'); } } catch (\Exception $e) { throw new namespace\Exception('instantiates \Nbe\Exception', ERROR_INFO, $e); } } catch (namespace\Exception $e) { echo 'error: '.$e->getMessage(); echo PHP_EOL; echo 'nested exception error: '.$e->getPrevious()->getMessage(); } File 1 File 2 namespace keyword
  • 33. Coming to an end, but first some Timeline changes PHP4 class constructor has the same name as the class > PHP5 class constructor is __construct but accepts PHP4 convention >5.3 namespaces are introduced, nothing changes >= 5.3.3 Backward compatibility change. Only __construct is now regarded as the constructor for namespaced code.
  • 34. And some cool resources The PHP manual http://www.php.net/namespaces Ralph Schindlers namespace convert tool https://github.com/ralphschindler/PHPTools Plus comments on it by Cal Evan http://blog.calevans.com/2010/03/27/zends-new-namespace-converter/ Google: php namespaces http://www.google.be/search?q=php+namespaces Zend Framework 2.0 Cookbook http://blog.nickbelhomme.com/php/zend-framework-2-0-cookbook_324
  • 35. And we reached the end, Any questions?
  • 36. The End! THANK YOU [email_address] Slideshare, Twitter, IRC: NickBelhomme http://blog.nickbelhomme.com