Into the ZF2 Service
Manager
Chris	
  Tankersley	
  
ZendCon	
  2015	
  
ZendCon	
  2015	
   1	
  
Who Am I
•  PHP	
  Programmer	
  for	
  over	
  10	
  years	
  
•  Been	
  using	
  ZF	
  since	
  ~0.5	
  
•  Daily	
  ZF2	
  user	
  
•  hBps://github.com/dragonmantank	
  
ZendCon	
  2015	
   2	
  
A running joke…
•  “Symfony2	
  is	
  a	
  PHP	
  script	
  that	
  turns	
  YAML	
  into	
  applicaNons”	
  
•  “Yeah,	
  but	
  Zend	
  Framework	
  2	
  is	
  a	
  PHP	
  script	
  that	
  turns	
  arrays	
  into	
  
applicaNons”	
  
ZendCon	
  2015	
   3	
  
ZendCon	
  2015	
   4	
  
It kind of is…
ZendCon	
  2015	
   5	
  
return	
  [	
  
	
  	
  	
  	
  'service_manager'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  'initializers'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobServiceJobServiceAwareInitializer'	
  
	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  	
  	
  	
  	
  'invokables'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobProcessorListener'	
  =>	
  'JobProcessorProcessorListener',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobServiceAccountListener'	
  =>	
  'JobServiceJobServiceListener’	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  	
  	
  	
  	
  'factories'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobService'	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  =>	
  'JobServiceJobServiceFactory',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobProcessor'	
  	
  	
  	
  	
  	
  	
  	
  	
  =>	
  'JobProcessorProcessorFactory',	
  
	
  	
  	
  	
  	
  	
  	
  	
  ]	
  
	
  	
  	
  	
  ]	
  
]	
  
Theater Magic
•  When	
  something	
  awesome	
  happens,	
  but	
  it’s	
  really	
  something	
  
mundane	
  controlling	
  it	
  in	
  the	
  background	
  
•  When	
  it	
  looks	
  good	
  from	
  25’	
  
ZendCon	
  2015	
   6	
  
The Service Manager
ZendCon	
  2015	
   7	
  
Service Locator
•  Container	
  for	
  storing	
  objects	
  or	
  condiNons	
  for	
  building	
  an	
  object	
  
•  Mostly	
  it’s	
  used	
  to	
  create	
  objects	
  
•  It	
  does	
  not	
  do	
  automaNc	
  dependency	
  injecNon	
  
•  It	
  is	
  not	
  global	
  (unless	
  you	
  make	
  it	
  global)	
  
ZendCon	
  2015	
   8	
  
What can we store in there?
•  Invokables	
  
•  Factories	
  
•  Abstract	
  Factories	
  
•  Delegators	
  
•  IniNalizers	
  
•  Aliases	
  
ZendCon	
  2015	
   9	
  
Standalone
$serviceManager	
  =	
  new	
  ZendServiceManagerServiceManager();	
  
$serviceManager-­‐>setService(‘MyService’,	
  $myService);	
  
	
  
$serviceManager-­‐>has(‘MyService’);	
  
$service	
  =	
  $serviceManager-­‐>get(‘MyService’);	
  
	
  
ZendCon	
  2015	
   10	
  
Built into ZF2 full-stack applications
•  Anything	
  that	
  is	
  ServiceLocatorAwareInterface	
  can	
  have	
  it	
  injected	
  
•  Controllers	
  are	
  the	
  most	
  common	
  
ZendCon	
  2015	
   11	
  
namespace	
  ApplicationController;	
  
	
  
use	
  ZendMvcControllerAbstractActionController;	
  
	
  
class	
  IndexController	
  extends	
  AbstractActionController	
  {	
  
	
  	
  	
  	
  public	
  function	
  indexAction()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $model	
  =	
  $this-­‐>getServiceLocator()-­‐>get(‘MyModel’);	
  
	
  	
  	
  	
  }	
  
}	
  
Stuff we can get from the Service Manager
ZendCon	
  2015	
   12	
  
Invokables
•  Any	
  sort	
  of	
  object	
  that	
  can	
  be	
  declared	
  with	
  ‘new’	
  and	
  has	
  no	
  
constructor	
  parameters	
  
ZendCon	
  2015	
   13	
  
class	
  MyClass	
  {	
  
	
  	
  	
  	
  public	
  function	
  foo()	
  {	
  ...	
  }	
  
	
  	
  	
  	
  public	
  function	
  bar()	
  {	
  ...	
  }	
  
}	
  
	
  
class	
  SimpleConstructor	
  {	
  
	
  	
  	
  	
  protected	
  $name;	
  
	
  	
  	
  	
  public	
  function	
  __construct()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>name	
  =	
  'baz';	
  
	
  	
  	
  	
  }	
  
}	
  
In ZF2
return	
  [	
  
	
  	
  	
  	
  'service_manager'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  'invokables'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobProcessorProcessorListener'	
  =>	
  'JobProcessorProcessorListener',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'JobServiceAccountListener'	
  =>	
  'JobServiceJobServiceListener'	
  
	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  ]	
  
]	
  
ZendCon	
  2015	
   14	
  
Quick Dependency Injection Tutorial
ZendCon	
  2015	
   15	
  
What is Dependency Injection?
•  InjecNng	
  dependencies	
  into	
  classes,	
  instead	
  of	
  having	
  the	
  class	
  create	
  
it	
  
•  Allows	
  for	
  much	
  easier	
  tesNng	
  
•  Allows	
  for	
  a	
  much	
  easier	
  Nme	
  swapping	
  out	
  code	
  
•  Reduces	
  the	
  coupling	
  that	
  happens	
  between	
  classes	
  
php[tek]	
  2015	
   16	
  
Method Injection
class	
  MapService	
  {	
  
	
  	
  	
  	
  public	
  function	
  getLatLong(GoogleMaps	
  $map,	
  $street,	
  $city,	
  $state)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $map-­‐>getLatLong($street	
  .	
  '	
  '	
  .	
  $city	
  .	
  '	
  '	
  .	
  $state);	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  public	
  function	
  getAddress(GoogleMaps	
  $map,	
  $lat,	
  $long)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $map-­‐>getAddress($lat,	
  $long);	
  
	
  	
  	
  	
  }	
  
}	
  
php[tek]	
  2015	
   17	
  
Constructor Injection
class	
  MapService	
  {	
  
	
  	
  	
  	
  protected	
  $map;	
  
	
  	
  	
  	
  public	
  function	
  __construct(GoogleMaps	
  $map)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>map	
  =	
  $map;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  getLatLong($street,	
  $city,	
  $state)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $this	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  -­‐>map	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  -­‐>getLatLong($street	
  .	
  '	
  '	
  .	
  $city	
  .	
  '	
  '	
  .	
  $state);	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
	
  	
  
php[tek]	
  2015	
   18	
  
Setter Injection
class	
  MapService	
  {	
  
	
  	
  	
  	
  protected	
  $map;	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  public	
  function	
  setMap(GoogleMaps	
  $map)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>map	
  =	
  $map;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  getMap()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $this-­‐>map;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  getLatLong($street,	
  $city,	
  $state)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $this-­‐>getMap()-­‐>getLatLong($street	
  .	
  '	
  '	
  .	
  $city	
  .	
  '	
  '	
  .	
  $state);	
  
	
  	
  	
  	
  }	
  
}	
  
	
  	
  
php[tek]	
  2015	
   19	
  
Back to the show
ZendCon	
  2015	
   20	
  
Factories
•  A	
  Factory	
  is	
  an	
  object/method	
  is	
  that	
  is	
  used	
  to	
  create	
  other	
  objects	
  
•  ZF2	
  Service	
  Manager	
  will	
  call	
  the	
  factory	
  when	
  an	
  object	
  is	
  pulled	
  out	
  
of	
  the	
  Service	
  Manager	
  
ZendCon	
  2015	
   21	
  
Why do we need factories?
Dependencies	
  
ZendCon	
  2015	
   22	
  
In ZF2
ZendCon	
  2015	
   23	
  
return	
  [	
  
	
  	
  	
  	
  'service_manager'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  ’factories'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'GoogleAdWordsAdWordsUserBuilder'	
  =>	
  'GoogleAdWordsGoogleAdWordsUserBuilderFactory',	
  
	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  ]	
  
]	
  
ZendCon	
  2015	
   24	
  
namespace	
  GoogleAdWords;	
  
	
  
class	
  GoogleAdWordsUserBuilder	
  
{	
  
	
  	
  	
  	
  public	
  function	
  __construct(array	
  $config)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>config	
  =	
  $config;	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
ZendCon	
  2015	
   25	
  
namespace	
  GoogleAdWords;	
  
	
  
use	
  ZendServiceManagerFactoryInterface;	
  
use	
  ZendServiceManagerServiceLocatorInterface;	
  
	
  
class	
  GoogleAdWordsUserBuilderFactory	
  implements	
  FactoryInterface	
  
{	
  
	
  	
  	
  	
  public	
  function	
  createService(ServiceLocatorInterface	
  $service)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $config	
  =	
  $service-­‐>get('Config');	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  GoogleAdWordsUserBuilder($config[‘google’]);	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
Abstract Factories
•  They	
  are	
  factories,	
  but	
  they	
  allow	
  the	
  creaNon	
  of	
  a	
  broad	
  range	
  of	
  
objects	
  instead	
  of	
  a	
  single	
  object	
  
•  The	
  factory	
  will	
  take	
  addiNonal	
  configuraNon	
  to	
  properly	
  create	
  the	
  
needed	
  object	
  
ZendCon	
  2015	
   26	
  
ZendCon	
  2015	
   27	
  
<?php	
  
	
  
namespace	
  MyProject;	
  
	
  
use	
  ZendDbTableGatewayTableGateway;	
  
use	
  ZendServiceManagerFactoryInterface;	
  
use	
  ZendServiceManagerServiceLocatorInterface;	
  
	
  
class	
  ProjectsTableFactory	
  implements	
  FactoryInterface	
  {	
  
	
  	
  	
  	
  public	
  function	
  createService(ServiceLocatorInterface	
  $serviceLocator)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $adapter	
  =	
  new	
  $serviceLocator-­‐>get('ZendDbAdapterAdapter');	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  TableGateway('projects',	
  $adapter);	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
class	
  CategoriesTableFactory	
  implements	
  FactoryInterface	
  {	
  
	
  	
  	
  	
  public	
  function	
  createService(ServiceLocatorInterface	
  $serviceLocator)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $adapter	
  =	
  new	
  $serviceLocator-­‐>get('ZendDbAdapterAdapter');	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  TableGateway('categories',	
  $adapter);	
  
	
  	
  	
  	
  }	
  
}	
  
In ZF2
ZendCon	
  2015	
   28	
  
return	
  [	
  
	
  	
  	
  	
  ’abstract_factories'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  ’MyProjectTableAbstractFactory’	
  
	
  	
  	
  	
  ]	
  
]	
  
ZendCon	
  2015	
   29	
  
<?php	
  
	
  
namespace	
  MyProject;	
  
	
  
use	
  ZendDbTableGatewayTableGateway;	
  
use	
  ZendServiceManagerAbstractFactoryInterface;	
  
use	
  ZendServiceManagerServiceLocatorInterface;	
  
	
  
class	
  TableAbstractFactory	
  implements	
  AbstractFactoryInterface	
  {	
  
	
  	
  	
  	
  public	
  function	
  canCreateServiceWithName(ServiceLocatorInterface	
  $sl,	
  $name,	
  $requestedName)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  preg_match("/Table$/",	
  $requestedName);	
  
	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  public	
  function	
  createServiceWithName(ServiceLocatorInterface	
  $sl,	
  $name,	
  $requestedName)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $adapter	
  =	
  $sl-­‐>get('ZendDbAdapterAdapter');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $tableName	
  =	
  str_replace('Table',	
  '',	
  $requestedName);	
  
	
  	
  	
  	
  	
  	
  	
  	
  $tableName	
  =	
  strtolower($tableName);	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  TableGateway($tableName,	
  $adapter);	
  
	
  	
  	
  	
  }	
  
}	
  
Initializers
•  Code	
  that	
  needs	
  to	
  run	
  ajer	
  an	
  object	
  is	
  created	
  
•  Really	
  helpful	
  for	
  when	
  lots	
  of	
  objects	
  need	
  addiNonal	
  objects	
  (like	
  
loggers)	
  all	
  across	
  the	
  applicaNon	
  
ZendCon	
  2015	
   30	
  
In ZF2
ZendCon	
  2015	
   31	
  
return	
  [	
  
	
  	
  	
  	
  ’initalizers'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  ’JobServiceJobServiceAwareInitializer’	
  
	
  	
  	
  	
  ]	
  
]	
  
ZendCon	
  2015	
   32	
  
<?php	
  
	
  
namespace	
  JobService;	
  
	
  
use	
  ZendServiceManagerInitializerInterface;	
  
use	
  ZendServiceManagerServiceLocatorAwareInterface;	
  
use	
  ZendServiceManagerServiceLocatorInterface;	
  
	
  
class	
  JobServiceAwareInitializer	
  implements	
  InitializerInterface	
  
{	
  
	
  	
  	
  	
  public	
  function	
  initialize($instance,	
  ServiceLocatorInterface	
  $serviceLocator)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (!$instance	
  instanceof	
  JobServiceAwareInterface)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  null;	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  /**	
  @var	
  JobServiceJobService	
  $jobService	
  */	
  
	
  	
  	
  	
  	
  	
  	
  	
  $jobService	
  =	
  $serviceLocator-­‐>get('JobService');	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  $instance-­‐>setJobService($jobService);	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
Delegators
•  They	
  are	
  actually	
  decorators	
  for	
  objects	
  that	
  don’t	
  exist	
  
•  They	
  are	
  like	
  iniNalizers	
  that	
  only	
  run	
  on	
  a	
  specific	
  key	
  
•  Allow	
  your	
  applicaNon	
  to	
  tweak	
  or	
  modify	
  3rd	
  party	
  objects	
  without	
  
having	
  to	
  extend	
  them	
  
ZendCon	
  2015	
   33	
  
In ZF2
ZendCon	
  2015	
   34	
  
return	
  [	
  
	
  	
  	
  	
  ’delgators'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  ’OtherVendorAccountAccountService’	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ‘MyProjectAccountAccountServiceDelegator’,	
  
	
  	
  	
  	
  	
  	
  	
  	
  ]	
  
	
  	
  	
  	
  ]	
  
]	
  
ZendCon	
  2015	
   35	
  
<?php	
  
	
  
namespace	
  MyProject;	
  
	
  
use	
  ZendServiceManagerDelegatorFactoryInterface;	
  
use	
  ZendServiceManagerServiceLocatorInterface;	
  
	
  
class	
  AccountServiceDelegator	
  implements	
  DelegatorFactoryInterface	
  {	
  
	
  	
  	
  	
  public	
  function	
  createDelegatorWithName(ServiceLocatorInterface	
  $sl,	
  $name,	
  $requestedName,	
  
$callback)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $originalService	
  =	
  $callback();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $accountService	
  =	
  new	
  MyProjectAccountAccountService($originalService);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $accountService;	
  
	
  	
  	
  	
  }	
  
}	
  
Aliases
•  Just	
  another	
  name	
  for	
  some	
  other	
  key	
  in	
  the	
  service	
  manager	
  
ZendCon	
  2015	
   36	
  
In ZF2
ZendCon	
  2015	
   37	
  
return	
  [	
  
	
  	
  	
  	
  ’aliases'	
  =>	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  ’MyProjectAccountOldAccountService’	
  =>	
  ‘MyProjectAccountNewAccountService’,	
  
	
  	
  	
  	
  ]	
  
]	
  
Bad Practices
ZendCon	
  2015	
   38	
  
Lots of Initializers
•  IniNalizers	
  run	
  ajer	
  every	
  object	
  is	
  created	
  
•  30	
  iniNalizers	
  *	
  50	
  objects	
  created	
  at	
  runNme	
  =	
  	
  1500	
  invocaNons	
  
•  Look	
  at	
  using	
  Factories	
  instead	
  to	
  inject	
  things	
  into	
  your	
  objects	
  
•  Look	
  at	
  using	
  Delegators	
  
ZendCon	
  2015	
   39	
  
Functions as Factories
•  The	
  Factory	
  system	
  will	
  actually	
  take	
  any	
  invokable	
  thing	
  as	
  a	
  factory	
  
•  That	
  means	
  you	
  can	
  use	
  closures	
  and	
  anonymous	
  classes	
  
ZendCon	
  2015	
   40	
  
ZendCon	
  2015	
   41	
  
return	
  [	
  
	
  	
  	
  	
  'factories'	
  =>	
  array(	
  
	
  	
  	
  	
  	
  	
  	
  	
  'CategoryService'	
  =>	
  function($sm)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $categoryService	
  =	
  new	
  CategoryService();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $categoryService-­‐>setCategoryTable($sm-­‐>get('CategoryTable'));	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  $categoryService;	
  
	
  	
  	
  	
  	
  	
  	
  	
  },	
  
	
  	
  	
  	
  	
  	
  	
  	
  'CategoryTable'	
  =>	
  function($sm)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $tableGateway	
  =	
  $sm-­‐>get('CategoryTableGateway');	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $table	
  =	
  new	
  CategoryTable($tableGateway);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  $table;	
  
	
  	
  	
  	
  	
  	
  	
  	
  },	
  
	
  	
  	
  	
  	
  	
  	
  	
  'CategoryTableGateway'	
  =>	
  function($sm)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $dbAdapter	
  =	
  $sm-­‐>get('ZendDbAdapterAdapter');	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $resultSetPrototype	
  =	
  new	
  ResultSet();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $resultSetPrototype-­‐>setArrayObjectPrototype(new	
  Category());	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  TableGateway('category',	
  $dbAdapter,	
  null,	
  $resultSetPrototype);	
  
	
  	
  	
  	
  	
  	
  	
  	
  },	
  
]	
  
Functions as Factories
•  This	
  makes	
  the	
  config	
  uncachable,	
  so	
  there	
  are	
  performance	
  issues	
  
ZendCon	
  2015	
   42	
  
Questions?
ZendCon	
  2015	
   43	
  
Thank You!
hBp://ctankersley.com	
  
chris@ctankersley.com	
  
@dragonmantank	
  
	
  
hBp://joind.in/talk/view/15534	
  
ZendCon	
  2015	
   44	
  

Into the ZF2 Service Manager

  • 1.
    Into the ZF2Service Manager Chris  Tankersley   ZendCon  2015   ZendCon  2015   1  
  • 2.
    Who Am I • PHP  Programmer  for  over  10  years   •  Been  using  ZF  since  ~0.5   •  Daily  ZF2  user   •  hBps://github.com/dragonmantank   ZendCon  2015   2  
  • 3.
    A running joke… • “Symfony2  is  a  PHP  script  that  turns  YAML  into  applicaNons”   •  “Yeah,  but  Zend  Framework  2  is  a  PHP  script  that  turns  arrays  into   applicaNons”   ZendCon  2015   3  
  • 4.
  • 5.
    It kind ofis… ZendCon  2015   5   return  [          'service_manager'  =>  [                  'initializers'  =>  [                          'JobServiceJobServiceAwareInitializer'                  ],                  'invokables'  =>  [                          'JobProcessorListener'  =>  'JobProcessorProcessorListener',                          'JobServiceAccountListener'  =>  'JobServiceJobServiceListener’                      ],                  'factories'  =>  [                          'JobService'                      =>  'JobServiceJobServiceFactory',                          'JobProcessor'                  =>  'JobProcessorProcessorFactory',                  ]          ]   ]  
  • 6.
    Theater Magic •  When  something  awesome  happens,  but  it’s  really  something   mundane  controlling  it  in  the  background   •  When  it  looks  good  from  25’   ZendCon  2015   6  
  • 7.
  • 8.
    Service Locator •  Container  for  storing  objects  or  condiNons  for  building  an  object   •  Mostly  it’s  used  to  create  objects   •  It  does  not  do  automaNc  dependency  injecNon   •  It  is  not  global  (unless  you  make  it  global)   ZendCon  2015   8  
  • 9.
    What can westore in there? •  Invokables   •  Factories   •  Abstract  Factories   •  Delegators   •  IniNalizers   •  Aliases   ZendCon  2015   9  
  • 10.
    Standalone $serviceManager  =  new  ZendServiceManagerServiceManager();   $serviceManager-­‐>setService(‘MyService’,  $myService);     $serviceManager-­‐>has(‘MyService’);   $service  =  $serviceManager-­‐>get(‘MyService’);     ZendCon  2015   10  
  • 11.
    Built into ZF2full-stack applications •  Anything  that  is  ServiceLocatorAwareInterface  can  have  it  injected   •  Controllers  are  the  most  common   ZendCon  2015   11   namespace  ApplicationController;     use  ZendMvcControllerAbstractActionController;     class  IndexController  extends  AbstractActionController  {          public  function  indexAction()  {                  $model  =  $this-­‐>getServiceLocator()-­‐>get(‘MyModel’);          }   }  
  • 12.
    Stuff we canget from the Service Manager ZendCon  2015   12  
  • 13.
    Invokables •  Any  sort  of  object  that  can  be  declared  with  ‘new’  and  has  no   constructor  parameters   ZendCon  2015   13   class  MyClass  {          public  function  foo()  {  ...  }          public  function  bar()  {  ...  }   }     class  SimpleConstructor  {          protected  $name;          public  function  __construct()  {                  $this-­‐>name  =  'baz';          }   }  
  • 14.
    In ZF2 return  [          'service_manager'  =>  [                  'invokables'  =>  [                          'JobProcessorProcessorListener'  =>  'JobProcessorProcessorListener',                          'JobServiceAccountListener'  =>  'JobServiceJobServiceListener'                  ],          ]   ]   ZendCon  2015   14  
  • 15.
    Quick Dependency InjectionTutorial ZendCon  2015   15  
  • 16.
    What is DependencyInjection? •  InjecNng  dependencies  into  classes,  instead  of  having  the  class  create   it   •  Allows  for  much  easier  tesNng   •  Allows  for  a  much  easier  Nme  swapping  out  code   •  Reduces  the  coupling  that  happens  between  classes   php[tek]  2015   16  
  • 17.
    Method Injection class  MapService  {          public  function  getLatLong(GoogleMaps  $map,  $street,  $city,  $state)  {                  return  $map-­‐>getLatLong($street  .  '  '  .  $city  .  '  '  .  $state);          }                    public  function  getAddress(GoogleMaps  $map,  $lat,  $long)  {                  return  $map-­‐>getAddress($lat,  $long);          }   }   php[tek]  2015   17  
  • 18.
    Constructor Injection class  MapService  {          protected  $map;          public  function  __construct(GoogleMaps  $map)  {                  $this-­‐>map  =  $map;          }          public  function  getLatLong($street,  $city,  $state)  {                  return  $this                          -­‐>map                          -­‐>getLatLong($street  .  '  '  .  $city  .  '  '  .  $state);          }   }         php[tek]  2015   18  
  • 19.
    Setter Injection class  MapService  {          protected  $map;                    public  function  setMap(GoogleMaps  $map)  {                  $this-­‐>map  =  $map;          }          public  function  getMap()  {                  return  $this-­‐>map;          }          public  function  getLatLong($street,  $city,  $state)  {                  return  $this-­‐>getMap()-­‐>getLatLong($street  .  '  '  .  $city  .  '  '  .  $state);          }   }       php[tek]  2015   19  
  • 20.
    Back to theshow ZendCon  2015   20  
  • 21.
    Factories •  A  Factory  is  an  object/method  is  that  is  used  to  create  other  objects   •  ZF2  Service  Manager  will  call  the  factory  when  an  object  is  pulled  out   of  the  Service  Manager   ZendCon  2015   21  
  • 22.
    Why do weneed factories? Dependencies   ZendCon  2015   22  
  • 23.
    In ZF2 ZendCon  2015   23   return  [          'service_manager'  =>  [                  ’factories'  =>  [                          'GoogleAdWordsAdWordsUserBuilder'  =>  'GoogleAdWordsGoogleAdWordsUserBuilderFactory',                  ],          ]   ]  
  • 24.
    ZendCon  2015  24   namespace  GoogleAdWords;     class  GoogleAdWordsUserBuilder   {          public  function  __construct(array  $config)  {                  $this-­‐>config  =  $config;          }   }    
  • 25.
    ZendCon  2015  25   namespace  GoogleAdWords;     use  ZendServiceManagerFactoryInterface;   use  ZendServiceManagerServiceLocatorInterface;     class  GoogleAdWordsUserBuilderFactory  implements  FactoryInterface   {          public  function  createService(ServiceLocatorInterface  $service)          {                  $config  =  $service-­‐>get('Config');                  return  new  GoogleAdWordsUserBuilder($config[‘google’]);          }   }    
  • 26.
    Abstract Factories •  They  are  factories,  but  they  allow  the  creaNon  of  a  broad  range  of   objects  instead  of  a  single  object   •  The  factory  will  take  addiNonal  configuraNon  to  properly  create  the   needed  object   ZendCon  2015   26  
  • 27.
    ZendCon  2015  27   <?php     namespace  MyProject;     use  ZendDbTableGatewayTableGateway;   use  ZendServiceManagerFactoryInterface;   use  ZendServiceManagerServiceLocatorInterface;     class  ProjectsTableFactory  implements  FactoryInterface  {          public  function  createService(ServiceLocatorInterface  $serviceLocator)  {                  $adapter  =  new  $serviceLocator-­‐>get('ZendDbAdapterAdapter');                  return  new  TableGateway('projects',  $adapter);          }   }     class  CategoriesTableFactory  implements  FactoryInterface  {          public  function  createService(ServiceLocatorInterface  $serviceLocator)  {                  $adapter  =  new  $serviceLocator-­‐>get('ZendDbAdapterAdapter');                  return  new  TableGateway('categories',  $adapter);          }   }  
  • 28.
    In ZF2 ZendCon  2015   28   return  [          ’abstract_factories'  =>  [                  ’MyProjectTableAbstractFactory’          ]   ]  
  • 29.
    ZendCon  2015  29   <?php     namespace  MyProject;     use  ZendDbTableGatewayTableGateway;   use  ZendServiceManagerAbstractFactoryInterface;   use  ZendServiceManagerServiceLocatorInterface;     class  TableAbstractFactory  implements  AbstractFactoryInterface  {          public  function  canCreateServiceWithName(ServiceLocatorInterface  $sl,  $name,  $requestedName)  {                  return  preg_match("/Table$/",  $requestedName);          }            public  function  createServiceWithName(ServiceLocatorInterface  $sl,  $name,  $requestedName)  {                  $adapter  =  $sl-­‐>get('ZendDbAdapterAdapter');                  $tableName  =  str_replace('Table',  '',  $requestedName);                  $tableName  =  strtolower($tableName);                    return  new  TableGateway($tableName,  $adapter);          }   }  
  • 30.
    Initializers •  Code  that  needs  to  run  ajer  an  object  is  created   •  Really  helpful  for  when  lots  of  objects  need  addiNonal  objects  (like   loggers)  all  across  the  applicaNon   ZendCon  2015   30  
  • 31.
    In ZF2 ZendCon  2015   31   return  [          ’initalizers'  =>  [                  ’JobServiceJobServiceAwareInitializer’          ]   ]  
  • 32.
    ZendCon  2015  32   <?php     namespace  JobService;     use  ZendServiceManagerInitializerInterface;   use  ZendServiceManagerServiceLocatorAwareInterface;   use  ZendServiceManagerServiceLocatorInterface;     class  JobServiceAwareInitializer  implements  InitializerInterface   {          public  function  initialize($instance,  ServiceLocatorInterface  $serviceLocator)          {                  if  (!$instance  instanceof  JobServiceAwareInterface)  {                          return  null;                  }                    /**  @var  JobServiceJobService  $jobService  */                  $jobService  =  $serviceLocator-­‐>get('JobService');                    $instance-­‐>setJobService($jobService);          }   }    
  • 33.
    Delegators •  They  are  actually  decorators  for  objects  that  don’t  exist   •  They  are  like  iniNalizers  that  only  run  on  a  specific  key   •  Allow  your  applicaNon  to  tweak  or  modify  3rd  party  objects  without   having  to  extend  them   ZendCon  2015   33  
  • 34.
    In ZF2 ZendCon  2015   34   return  [          ’delgators'  =>  [                  ’OtherVendorAccountAccountService’  =>  [                          ‘MyProjectAccountAccountServiceDelegator’,                  ]          ]   ]  
  • 35.
    ZendCon  2015  35   <?php     namespace  MyProject;     use  ZendServiceManagerDelegatorFactoryInterface;   use  ZendServiceManagerServiceLocatorInterface;     class  AccountServiceDelegator  implements  DelegatorFactoryInterface  {          public  function  createDelegatorWithName(ServiceLocatorInterface  $sl,  $name,  $requestedName,   $callback)  {                  $originalService  =  $callback();                  $accountService  =  new  MyProjectAccountAccountService($originalService);                                    return  $accountService;          }   }  
  • 36.
    Aliases •  Just  another  name  for  some  other  key  in  the  service  manager   ZendCon  2015   36  
  • 37.
    In ZF2 ZendCon  2015   37   return  [          ’aliases'  =>  [                  ’MyProjectAccountOldAccountService’  =>  ‘MyProjectAccountNewAccountService’,          ]   ]  
  • 38.
  • 39.
    Lots of Initializers • IniNalizers  run  ajer  every  object  is  created   •  30  iniNalizers  *  50  objects  created  at  runNme  =    1500  invocaNons   •  Look  at  using  Factories  instead  to  inject  things  into  your  objects   •  Look  at  using  Delegators   ZendCon  2015   39  
  • 40.
    Functions as Factories • The  Factory  system  will  actually  take  any  invokable  thing  as  a  factory   •  That  means  you  can  use  closures  and  anonymous  classes   ZendCon  2015   40  
  • 41.
    ZendCon  2015  41   return  [          'factories'  =>  array(                  'CategoryService'  =>  function($sm)  {                          $categoryService  =  new  CategoryService();                          $categoryService-­‐>setCategoryTable($sm-­‐>get('CategoryTable'));                          return  $categoryService;                  },                  'CategoryTable'  =>  function($sm)  {                          $tableGateway  =  $sm-­‐>get('CategoryTableGateway');                          $table  =  new  CategoryTable($tableGateway);                          return  $table;                  },                  'CategoryTableGateway'  =>  function($sm)  {                          $dbAdapter  =  $sm-­‐>get('ZendDbAdapterAdapter');                          $resultSetPrototype  =  new  ResultSet();                          $resultSetPrototype-­‐>setArrayObjectPrototype(new  Category());                          return  new  TableGateway('category',  $dbAdapter,  null,  $resultSetPrototype);                  },   ]  
  • 42.
    Functions as Factories • This  makes  the  config  uncachable,  so  there  are  performance  issues   ZendCon  2015   42  
  • 43.
  • 44.
    Thank You! hBp://ctankersley.com   chris@ctankersley.com   @dragonmantank     hBp://joind.in/talk/view/15534   ZendCon  2015   44