Is it possible to create a function that going be automatically called when each function are called?
I want that the result do this:
before_functions()
function_1()
before_functions()
function_2()
before_functions()
function_3()
But i want a file wit the function:
function before_functions(){} -> call before each function
and another file where I call functions:
function_1()
function_2()
function_3()
But I won't call the before_functions in each function..
There are different approaches to solve your problem. Some of them are mentioned in the comments already. Let us take the simplest approaches for solving your issue.
The magic method __call()
As lovelace said in the comments, there is already a simple solution for your problem stated in another stack overflow article. It uses PHPs own magic method __call(). Let 's have a look at a simple example.
class Foo
{
protected function before() : void
{
echo "before";
}
public function after() : void
{
echo "after";
}
public function __call($method, $arguments)
{
if (method_exists($this, $method)) {
$this->before();
return call_user_func_array(array($this, $method), $arguments);
}
}
}
// Testing
$class = new Foo();
$class->after(); // echoes "before->after"
As you can see the magic method __call provides proper handling for your purpose. First it checks, if the called method exists and after that it executes the before method before the called method is executed. The before method is called automatically, when you call a class method, that exists.
The callback approach
As also mentioned in the comments a callback function could be a possible solution without handling class instances. Let 's have a look at the callback example.
$callback = function()
{
echo "before->";
}
function foo(callable $callback, $bla)
{
$callback();
echo $bla;
}
// example code
foo($callback, 'go and make some coffee');
// output: "before->go and make some coffee"
This approach is even simpler as using the __call method, because you need just a callable function as parameter for your functions. Easy, hm?
The observer pattern
The observer pattern came with the standard php library in php5 and is more complex. I guess way too complex for your use case. To keep it complete, here 's a short example, how the observer pattern could be a usable solution to your issue.
class Group implements SplSubject
{
/**
* persons in this group
* #var \SplObjectStorage
*/
protected $persons;
/**
* observer active in this group
* #var \SplObjectStorage
*/
protected $observers;
/**
* the person, which actually speaks
* #var Person
*/
protected $speaker;
/**
* Initializes our class members and sets an observer for this group
*/
public function __construct()
{
$this->persons = new \SplObjectStorage();
$this->observers = new \SplObjectStorage();
$onSpeakObserver = new OnSpeakObserver($who, $what);
$this->attach($onSpeakObserver);
}
public function add(Person $person) {
$this->persons->attach($person);
}
public function speak(Person $who, $what) {
echo $who . " says: " . $what . "<br>";
$this->speaker = $who;
$this->notify();
}
public function getSpeaker() {
return $this->speaker;
}
public function getGroup() {
return $this->persons;
}
public function attach(\SplObserver $observer) {
$this->observers->attach($observer);
}
public function detach(\SplObserver $observer) {
$this->observers->attach($observer);
}
public function notify() {
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
This is our basic class called group, which should be observed. A class, which should be observed, is always called the "subject". A subject takes one ore more observers, which are called by the notify method of the subject. A group consists of several people and a speaker. There is always one speaker and the other persons are listeners, which can react, when the speaker says something. For the reaction of the listeners we need an observer. This observer listens, if the speaker says something. The observer is added directly in the constructor of the group.
This class implements the \SplSubject interface, which brings us the methods attach, detach and notify for handling the observer, we attach to the group. Next we need the classes for a person and the observer itself.
class Person
{
protected $name = '';
public function __construct(string $name) : void
{
$this->name = $name;
}
public function __toString() : string
{
return $this->name;
}
}
A simple person with a name.
class OnSpeakObserver implements \SplObserver
{
public function update(\SplSubject $subject)
{
foreach ($subject->getGroup() as $person) {
if ($person !== $subject->getSpeaker()) {
echo $person . " says: me!<br>";
}
}
}
}
This is our observer, which implements the native \SplObserver interface, which forces us to use the update method. This method is called every time, when a person in the group speaks.
With this the classes, we have a simple observer pattern. In this simple example the observer forces a reaction every time a person in a group says something.
// open a group (the subject, which is observed)
$friends = new Group();
// add some persons to our group
$sarah = new Person('Sarah');
$friends->add($sarah);
$nicole = new Person('Nicole');
$friends->add($nicole);
$marcel = new Person('Marcel');
$friends->add($marcel);
$steffen = new Person('Steffen');
$friends->add($steffen);
// Marcel says ...
$friends->speak($marcel, 'Who likes the observer pattern?');
// result:
// Marcel says: Who likes the observer pattern?
// Sarah says: me!
// Nicole says: me!
// Steffen says: me!
You could transfer this little example to solve your problem. An observer could listen on the execution of your functions and every time one of your functions is called, the observer could execute another function before. As shown in this example, the observer does nothing more than executing, after a person in a group has said something. Same goes for your issue. It all depends on when the notify method of the subject is called.
If you have any questions feel free to ask.
Related
I have the following classes :
<?php
class SaveEvent implements EventInterface
{
private $_path;
public function __construct($path) { $this->_path = $path; }
public function getName() { return 'save'; }
public function getPath() { return $this->_path; }
}
class Observer implements ObserverInterface
{
public function update(EventInterface $event)
{
switch ($event->getName()) {
case 'save':
$path = $event->getPath();
file_put_contents($path, 'File saved');
break;
case 'quit':
// Other event
}
}
}
As you can see, my "update" method takes in parameter an EventInterface and according to the kind of event will trigger a specific process. It's about the same implementation than SplSubject / SplObserver but instead of passing my subject to my observers I will pass an event (that eventually can contain data).
My observer will listen for a "save" event, event linked to a file path, and will stored the string "File saved" on this path.
Is it a bad practice to accept an "interfaced" parameter, check its concrete type and to consider it like its concrete type after?
If yes which solution do you propose to solve this problem?
PS: I'm not satisfied on title and tags I set for this topic, if you have better please help me :)
The only issue I see here is that you are expecting one of several specific implementations of the interface. Sometimes that is OK, if you are optimizing, but I'd normally expect to see that with declared class names, such as:
if ($event instanceof MyConcreteEvent) {
// ...
}
If you are implementing an event dispatcher, then you would subscribe classes to the Observer which listen for a specific $event->getName().
The observer would then iterate over the subscribers, calling each one. If there are no subscribers listening for the event, then nothing should happen.
Checkout http://symfony.com/doc/current/components/event_dispatcher/index.html for information on events.
I know the Observer and Event Dispatcher are separate patterns, but at their hearts they are the same thing.
It is a good practice because you might have another class (implementing the same interface) that has a similar/exact behavior but with different algorithm and it can be easily decoupled.
This is a strategy desing pattern (see more patterns here: http://www.phptherightway.com/pages/Design-Patterns.html#strategy )
Example
class YYYScraper implements LinkScraper
{
public function getLinks() {
//gets links from the site www.yyy.com specific for this because the site has a different structure from the class below
}
}
class XXXScraper implements LinkScraper
{
public function getLinks() {
//gets links from the site www.xxx.com
}
}
class ProcessService
{
public function gatherLinks(LinkScraper $linkScraper)
{
$linkScraper->getLinks();
//save them or smth
}
}
In your example update method tends to become bigger and bigger, and do too much. It becomes difficult to read.
The best choice would be to implement each event type as a method in the observer class like:
class Observer implements ObserverInterface
{
public function save(SaveEvent $event)
{
$path = $event->getPath();
file_put_contents($path, 'File saved');
}
public function quit(QuitEvent $event)
{
// Other event
}
}
Hope it helps.
Lately I'm giving a try to phpspec. It works great, but I have got a problem with testing command handlers. For example in PHPUnit I test it that way:
/**
* #test
*/
public function it_should_change_an_email()
{
$this->repository->add($this->employee);
$this->handler->changeEmail(
new ChangeEmailCommand(
$this->employee->username()->username(),
'new#email.com'
)
);
Asserts::assertEquals(new Email('new#email.com'), $this->employee->email());
}
and setup:
protected function setUp()
{
$this->repository = new InMemoryEmployeeRepository();
$this->createEmployee();
$this->handler = new EmployeeCommandHandler($this->repository);
}
The main point is that this test make assertions on the Employee object to check if CommandHandler is working good. But in phpspec I can't make assertion on different object than the specifying one, in this case I can only make assertion on my CommandHandler. So how I can test a command handler in phpspec?
EDIT
Maybe spies are the way to go:
class EmployeeCommandHandlerSpec extends ObjectBehavior
{
const USERNAME = 'johnny';
/** #var EmployeeRepository */
private $employeeRepository;
public function let(EmployeeRepository $employeeRepository)
{
$this->employeeRepository = $employeeRepository;
$this->beConstructedWith($employeeRepository);
}
public function it_changes_the_employee_email(Employee $employee)
{
$this->givenEmployeeExists($employee);
$this->changeEmail(
new ChangeEmailCommand(self::USERNAME, 'new#email.com')
);
$employee->changeEmail(new Email('new#email.com'))->shouldHaveBeenCalled();
}
private function givenEmployeeExists(Employee $employee)
{
$this->employeeRepository->employeeWithUsername(new EmployeeUsername(self::USERNAME))
->shouldBeCalled()
->willReturn($employee);
}
}
Employee class I've already speced. So, maybe, in command handler it'll be enough to just check if the method of the Employee has been called. What do you think about it? Am I going in good direction?
Messaging
Indeed, you shouldn't verify the state, but expect certain interactions between objects. That's what OOP is about afterall - messaging.
The way you've done it in PHPUnit is state verification. It forces you to expose the state as you need to provide a "getter", which is not always desired. What you're interested in is that Employee's email was updated:
$employee->updateEmail(new Email('new#email.com'))->shouldBeCalled();
The same can be achieved with spies if you prefer:
$employee->updateEmail(new Email('new#email.com'))->shouldHaveBeenCalled();
Command/Query Separation
We usually only need to state our expectations against methods that have side effects (command methods from Command/Query separation). We mock them.
Query methods do not need to be mocked, but stubbed. You don't really expect that EmployeeRepository::employeeWithUsername() should be called. Doing so we're making assumptions about implementation which in turn will make refactoring harder. All you need is stubbing it, so if a method is called it returns a result:
$employeeRepository->employeeWithUsername(new EmployeeUsername(self::USERNAME))
->willReturn($employee);
Full example
class EmployeeCommandHandlerSpec extends ObjectBehavior
{
const USERNAME = 'johnny';
public function let(EmployeeRepository $employeeRepository)
{
$this->beConstructedWith($employeeRepository);
}
public function it_changes_the_employee_email(
EmployeeRepository $employees, Employee $employee
) {
$this->givenEmployeeExists($employees, $employee);
$this->changeEmail(
new ChangeEmailCommand(self::USERNAME, 'new#email.com')
);
$employee->changeEmail(new Email('new#email.com'))->shouldHaveBeenCalled();
}
private function givenEmployeeExists(
EmployeeRepository $employees, Employee $employee
) {
$employees->employeeWithUsername(new EmployeeUsername(self::USERNAME))
->willReturn($employee);
}
}
I've been reading / watching a lot of recommended material, most recently this - MVC for advanced PHP developers. One thing that comes up is Singletons are bad, they create dependency between classes, and Dependency Injection is good as it allows for unit testing and decoupling.
That's all well and good until I'm writing my program. Let's take a Product page in a eshop as an example. First of all I have my page:
class Page {
public $html;
public function __construct() {
}
public function createPage() {
// do something to generate the page
}
public function showPage() {
echo $this->html;
}
}
All fine so far, but the page needs a product, so let's pass one in:
class Page {
public $html;
private $product;
public function __construct(Product $product) {
$this->product = $product;
}
public function createPage() {
// do something to generate the page
}
public function showPage() {
echo $this->html;
}
}
I've used dependency injection to avoid making my page class dependent on a product. But what if page had several public variables and whilst debugging I wanted to see what was in those. No problem, I just var_dump() the page instance. It gives me all the variables in page, including the product object, so I also get all the variables in product.
But product doesn't just have all the variables containing all the details of the product instantiated, it also had a database connection to get those product details. So now my var_dump() also has the database object in it as well. Now it's starting to get a bit longer and more difficult to read, even in <pre> tags.
Also a product belongs to one or more categories. For arguments sake let's say it belongs to two categories. They are loaded in the constructor and stored in a class variable containing an array. So now not only do I have all the variables in product and the database connection, but also two instances of the category class. And of course the category information also had to be loaded in from the database, so each category instance also has a database private variable.
So now when I var_dump() my page I have all the page variables, all the product variables, multiples of the category variables in an array, and 3 copies of the database variables (one from the products instance and one from each of the category instances). My output is now huge and difficult to read.
Now how about with singletons? Let's look at my page class using singletons.
class Page {
public $html;
public function __construct() {
}
public function createPage() {
$prodId = Url::getProdId();
$productInfo = Product::instance($prodId)->info();
// do something to generate the page
}
public function showPage() {
echo $this->html;
}
}
And I use similar singletons inside the Product class as well. Now when I var_dump() my Page instance I only get the variables I wanted, those belonging to the page and nothing else.
But of course this has created dependencies between my classes. And in unit testing there's no way to not call the product class, making unit testing difficult.
How can I get all the benefits of dependency injection but still make it easy to debug my classes using var_dump()? How can I avoid storing all these instances as variables in my classes?
I'll try to write about several things here.
About the var_dump():
I'm using Symfony2 as a default framework, and sometimes, var_dump() is the best option for a quick debug. However, it can output so much information, that there is no way you're going to read all of it, right? Like, dumping Symfony's AppKernel.php, or, which is more close to your case, some service with an EntityManager dependency. IMHO, var_dump() is nice when you debugging small bits of code, but large and complex product make var_dump() ineffective. Alternative for me is to use a "real" debugger, integrated with your IDE. With xDebug under PhpStorm I have no real need of var_dump() anymore.
Useful link about "Why?" and "How-to?" is here.
About the DI Container:
Big fan of it. It's simple and makes code more stable; it's common in modern applications. But I agree with you, there is a real problem behind: nested dependencies. This is over-abstraction, and it will add complexity by adding sometimes unnecessary layers.
Masking the pain by using a dependency injection container is making
your application more complex.
If you want to remove DIC from your application, and you actually can do it, then you don't need DIC at all. If you want alternative to DIC, well... Singletons are considered bad practice for not testable code and a huge state space of you application. Service locator to me has no benefits at all. So looks like there is the only way, to learn using DI right.
About your examples:
I see one thing immediately - injecting via construct(). It's cool, but I prefer optional passing dependency to the method that requires it, for example via setters in services config.yml.
class Page
{
public $html;
protected $em;
protected $product;
public function __construct(EntityManager $em) {
$this->em = $em;
}
//I suppose it's not from DB, because in this case EM handles this for you
protected function setProduct(Product $product)
{
$this->product = $product;
}
public function createPage()
{
//$this->product can be used here ONLY when you really need it
// do something to generate the page
}
public function showPage()
{
echo $this->html;
}
}
I think it gives needed flexibility when you need only some objects during execution, and at the given moment you can see inside your class only properties you need.
Conclusion
Excuse me for my broad and somewhat shallow answer. I really think that there is no direct answer to your question, and any solution would be opinion based. I just hope that you might find that DIC is really the best solution with limited downside, as well as integrated debuggers instead of dumping the whole class (constructor, service, etc...).
I exactly know that it's possible to reach result what you wish, and don't use extreme solutions.
I am not sure that my example is good enough for you, but it has: di and it easy to cover by unit test and var_dump will be show exactly what you wish, and i think it encourage SRP.
<?php
class Url
{
public static function getProdId()
{
return 'Category1';
}
}
class Product
{
public static $name = 'Car';
public static function instance($prodId)
{
if ($prodId === 'Category1') {
return new Category1();
}
}
}
class Category1 extends Product
{
public $model = 'DB9';
public function info()
{
return 'Aston Martin DB9 v12';
}
}
class Page
{
public $html;
public function createPage(Product $product)
{
// Here you can do something more to generate the page.
$this->html = $product->info() . PHP_EOL;
}
public function showPage()
{
echo $this->html;
}
}
$page = new Page();
$page->createPage(Product::instance(Url::getProdId()));
$page->showPage();
var_export($page);
Result:
Aston Martin DB9 v12
Page::__set_state(array(
'html' => 'Aston Martin DB9 v12
',
))
Maybe this will help you:
class Potatoe {
public $skin;
protected $meat;
private $roots;
function __construct ( $s, $m, $r ) {
$this->skin = $s;
$this->meat = $m;
$this->roots = $r;
}
}
$Obj = new Potatoe ( 1, 2, 3 );
echo "<pre>\n";
echo "Using get_object_vars:\n";
$vars = get_object_vars ( $Obj );
print_r ( $vars );
echo "\n\nUsing array cast:\n";
$Arr = (array)$Obj;
print_r ( $Arr );
This will returns:
Using get_object_vars:
Array
(
[skin] => 1
)
Using array cast:
Array
(
[skin] => 1
[ * meat] => 2
[ Potatoe roots] => 3
)
See the rest here http://php.net/manual/en/function.get-object-vars.php
The short answer is, yes you can avoid many private variables and using dependency injection. But (and this is a big but) you have to use something like an ServiceContainer or the principle of it.
The short answer:
class A
{
protected $services = array();
public function setService($name, $instance)
{
$this->services[$name] = $instance;
}
public function getService($name)
{
if (array_key_exists($name, $this->services)) {
return $this->services[$name];
}
return null;
}
private function log($message, $logLevel)
{
if (null === $this->getService('logger')) {
// Default behaviour is to log to php error log if $logLevel is critical
if ('critical' === $logLevel) {
error_log($message);
}
return;
}
$this->getService('logger')->log($message, $logLevel);
}
public function actionOne()
{
echo 'Action on was called';
$this->log('Action on was called', 0);
}
}
$a = new A();
// Logs to error log
$a->actionOne();
$a->setService('logger', new Logger());
// using the logger service
$a->actionOne();
With that class, you have just one protected variable and you are able to add any functionality to the class just by adding a service.
A more complexer example with an ServiceContainer can be somthing like that
<?php
/**
* Class ServiceContainer
* Manage our services
*/
class ServiceContainer
{
private $serviceDefinition = array();
private $services = array();
public function addService($name, $class)
{
$this->serviceDefinition[$name] = $class;
}
public function getService($name)
{
if (!array_key_exists($name, $this->services)) {
if (!array_key_exists($name, $this->serviceDefinition)) {
throw new \RuntimeException(
sprintf(
'Unkown service "%s". Known services are %s.',
$name,
implode(', ', array_keys($this->serviceDefinition))
)
);
}
$this->services[$name] = new $this->serviceDefinition[$name];
}
return $this->services[$name];
}
}
/**
* Class Product
* Part of the Model. Nothing too complex
*/
class Product
{
public $id;
public $info;
/**
* Get info
*
* #return mixed
*/
public function getInfo()
{
return $this->info;
}
}
/**
* Class ProductManager
*
*/
class ProductManager
{
public function find($id)
{
$p = new Product();
$p->id = $id;
$p->info = 'Product info of product with id ' . $id;
return $p;
}
}
class UnusedBadService
{
public function _construct()
{
ThisWillProduceAnErrorOnExecution();
}
}
/**
* Class Page
* Handle this request.
*/
class Page
{
protected $container;
/**
* Set container
*
* #param ServiceContainer $container
*
* #return ContainerAware
*/
public function setContainer(ServiceContainer $container)
{
$this->container = $container;
return $this;
}
public function get($name)
{
return $this->container->getService($name);
}
public function createPage($productId)
{
$pm = $this->get('product_manager');
$productInfo = $pm->find($productId)->getInfo();
// do something to generate the page
return sprintf('<html><head></head><body><h1>%s</h1></body></html>', $productInfo);
}
}
$serviceContainer = new ServiceContainer();
// Add some services
$serviceContainer->addService('product_manager', 'ProductManager');
$serviceContainer->addService('unused_bad_service', 'UnusedBadService');
$page = new Page();
$page->setContainer($serviceContainer);
echo $page->createPage(1);
var_dump($page);
You can see, if you look at the var_dump output, that just the services, you called are in the output.
So this is small, fast and sexy ;)
I am working on a script, and I need to make it pluginable. Now the syntax I have come with and which should work for me, is to make it use classes. For example, in order to create a new plugin that would be run when a certain point (hook) is reached, you would declare a new class. What I am not sure is how would the hook be specified in that syntax, so I am looking for suggestions.
Syntax example:
<?php
class ScriptPlugin
{
function runPlugin() {} // would be run when the time has to come to execute this plugin
}
?>
Also, if that syntax is not going to work, it would be great if you guys could give me a good syntax example.
There is the Observer Pattern which comes to mind. Plugins will register themselves and will get notifications when the hook is invoked.
Another thing that comes to mind are callbacks in PHP. And there was a similar question already with an answer that came to mind. It shows hooks based on callbacks.
The Observer Pattern runs a bit short because with hooks you often want to provide things like arguments and a return value. The linked answer which uses callbacks does not have this either, so I wrote a little Hooks example class that provides named hooks/events to registered callbacks, and a way to register your own classes, e.g. a plugin.
The idea is pretty basic:
A hook has a name and zero or more callbacks attached.
All hooks are managed in a Hooks class.
The main code invokes hooks by calling a function on the Hooks object.
Plugins (and other classes) can register their own callbacks, which is done with the help of the Registerable interface.
Some example code with one plugin and two hooks:
<?php
Namespace Addon;
class Hooks
{
private $hooks = array();
private $arguments;
private $name;
private $return;
public function __call($name, array $arguments)
{
$name = (string) $name;
$this->name = $name;
$this->arguments = $arguments;
$this->return = NULL;
foreach($this->getHooks($name) as $hook)
{
$this->return = call_user_func($hook, $this);
}
return $this->return;
}
public function getHooks($name)
{
return isset($this->hooks[$name]) ? $this->hooks[$name] : array();
}
public function getArguments()
{
return $this->arguments;
}
public function getName()
{
return $this->name;
}
public function getReturn()
{
return $this->return;
}
public function setReturn($return)
{
$this->return = $return;
}
public function attach($name, $callback)
{
$this->hooks[(string) $name][] = $callback;
}
public function register(Registerable $plugin)
{
$plugin->register($this);
}
}
interface Registerable
{
public function register(Hooks $hooks);
}
class MyPlugin implements Registerable
{
public function register(Hooks $hooks)
{
$hooks->attach('postPublished', array($this, 'postPublished'));
$hooks->attach('postDisplayFilter', array($this, 'filterToUpper'));
}
public function postPublished()
{
echo "MyPlugin: postPublished.\n";
}
public function filterToUpper(Hooks $context)
{
list($post) = $context->getArguments();
return strtoupper($post);
}
}
$hooks = new Hooks();
$plugin = new MyPlugin();
$hooks->register($plugin);
$hooks->postPublished();
echo $hooks->postDisplayFilter("Some post text\n");
I've done it this way to prevent that each Plugin must have a concrete base class only because it wants to make use of hooks. Additionally everything can register hooks, the only thing needed is a callback. For example an anonymous function:
$hooks->attach('hookName', function() {echo "Hook was called\n";});
You can however create yourself a plugin base class, that for example implements the register function and will automatically register functions that have a certain docblock tag or the name of a function
class MyNewPlugin extends PluginSuper
{
/**
* #hook postPublished
*/
public function justAnotherFunction() {}
public hookPostPublished() {}
}
The superclass can make use of Reflection to add the hooks on runtime. However reflection can slow things down and might make things harder to debug.
Let's say a plugin is like :
class NewsPlugin extends Plugin
{
function onCreate($title)
{
# Do some stuff
}
}
Then when you create a news you can just call onCreate on all plugins registered.
I would make a base abstract class with functions for all the hooks that could possibly be called.
abstract class Plugin {
abstract function yourHook();
}
All plugin classes should inherit this base class, and will override those base functions with their own.
class SomePlugin extends Plugin {
function yourHook() {
echo 'yourHook() Called!';
}
}
Now when your program runs, you need to find all of those plugin files to include, and somehow put them into an array, such as $plugins. See this article: https://stackoverflow.com/a/599694/362536
foreach (glob("classes/*.php") as $filename)
{
include $filename;
}
(From Karsten)
Define a function accessible from everything, such as registerPlugin():
function registerPlugin($classname) {
$plugins[] = new $classname();
}
Make the top line of each plugin file like this (prior to the class):
registerPlugin('SomePlugin');
If you do this, you'll have an array in $plugins with instances of each plugin. At the appropriate time, you can do something like this:
foreach ($plugins as $plugin) {
$plugin->yourHook();
}
As an alternative, it may be more appropriate to use interfaces in your case, instead. You should decide which method is best for your application.
I'm working on a test in phpunit and I'm running into an issue. I have a public function on my class that I am trying to test. Depending on the parameters passed in to the method, a protected function also in my test class will be called one or two times. I currently have a test in place to check that the return data is correct, but I would also like to make sure the protected method is being called the correct number of times.
I know that a mock object will allow me to count the number of times a function is called, but it will also override the value returned by the protected function. I tried using a mock object with no "will" section, but it would just return null, not the actual value for the protected method.
ExampleClass
public function do_stuff($runTwice){
$results = do_cool_stuff();
if($runTwice){
$results = 2 * do_cool_stuff();
}
return $results;
}
protected function do_cool_stuff()
{
return 2;
}
In my test, I want to check whether do_cool_stuff() was called once or twice, but I still want the return values of both functions to be the same so I can test those as well in my unit test.
tl;dr
I want to count the number of times a protected method in my test object is called (like you can do with a mock object) but I still want all the methods in my test method to return their normal values (not like a mock object).
Alternatively, revert back to rolling your own testable stand-in. The following aint pretty, but you get the idea:
class ExampleClass {
public function do_stuff($runTwice) {
$results = $this->do_cool_stuff();
if ($runTwice) {
$results = 2 * $this->do_cool_stuff();
}
return $results;
}
protected function do_cool_stuff() {
return 2;
}
}
class TestableExampleClass extends ExampleClass {
/** Stores how many times the do_cool_stuff method is called */
protected $callCount;
function __construct() {
$this->callCount = 0;
}
function getCallCount() {
return $this->callCount;
}
/** Increment the call counter, and then use the base class's functionality */
protected function do_cool_stuff() {
$this->callCount++;
return parent::do_cool_stuff();
}
}
class ExampleClassTest extends PHPUnit_Framework_TestCase {
public function test_do_stuff() {
$example = new ExampleClass();
$this->assertEquals(2, $example->do_stuff(false));
$this->assertEquals(4, $example->do_stuff(true));
}
public function test_do_cool_stuff_is_called_correctly() {
// Try it out the first way
$firstExample = new TestableExampleClass();
$this->assertEquals(0, $firstExample->getCallCount());
$firstExample->do_stuff(false);
$this->assertEquals(1, $firstExample->getCallCount());
// Now test the other code path
$secondExample = new TestableExampleClass();
$this->assertEquals(0, $secondExample->getCallCount());
$secondExample->do_stuff(true);
$this->assertEquals(2, $secondExample->getCallCount());
}
}
I wonder though whether counting the number of times a protected method has been called is really a good test. It's coupling your test to the implementation pretty hard. Does it really matter whether it is called twice, or are you more interested in the interactions with other objects? Or maybe this is pointing towards do_cool_stuff needing a refactor into two separate methods:
class ExampleClass {
public function do_stuff($runTwice) {
if ($runTwice) {
return $this->do_cool_stuff_twice();
} else {
return $this->do_cool_stuff_once();
}
}
//...
}
Try setting a global variable prior to utilizing the class.
$IAmDeclaredOutsideOfTheFunction;
then use it to store the count and simply check it after your functions and classes have been called.