One of the most prolific parts of Zend Framework 2 is the Service Manager. Its many nooks and crannies dictate much of what happens inside our Zend Framework 2 applications and is incredibly powerful. Let's look into exactly what the Service Manager allows us to do and how we can take advantage of it for cleaner, and faster, code.
1. Into the ZF2 Service
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
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
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 we store in there?
• Invokables
• Factories
• Abstract
Factories
• Delegators
• IniNalizers
• Aliases
ZendCon
2015
9
11. 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’);
}
}
12. Stuff we can get 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';
}
}
16. 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
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
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 we need factories?
Dependencies
ZendCon
2015
22
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);
}
}
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
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
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