I've been trying to adopt TDD methodologies in my projects lately but I have a hard time knowing how to test certain pieces of code. I've read quite a bit on the subject but I have a hard time taking that and putting it into practice. Since that is the case, I'm going to post my method and ask how you would try to test it.
public function simulate(){
while (!isComplete()) {
if ($this->currentOuts == 3) {
advanceInning();
} else {
$batter = getBatter();
$pitcher = getPitcher();
$atBat = new AtBat($batter, $pitcher);
$result = $atBat->simulate();
handleAtBatResult();
}
}
}
Assume that all function calls inside of simulate are being tested properly. Is there really anything else to test? Maybe that certain functions are called? Does the lack of obvious testing (at least to me) point to design issues?
When starting out using TDD I ended up asking the same questions you are asking here. After some research, and several weeks of working with unit tests etc, I came up with two terms; "flow testing", and "module testing".
Module Testing: As engineers we should be working hard to follow the DRY (don't repeat yourself) principle, as such, we end up with abstract pieces of code, which get pushed to the lowest layer of application, so they can be used anywhere. These pieces of code, whether methods of a class or stand alone functions should be atomically testable, meaning that there is the lowest possible dependence on any other modules, functions, etc. Obviously this becomes avoidable as you work on methods/functions which incorporate several modules, but this is where flow testing comes into play.
Flow Testing: With all of our basic modules in a testable state, we need to also be able to test them in scenarios commensurate with real world requirements. In order to flow test correctly, we need to establish what I refer to as "known goods". What this means is we construct data which mirrors the return value of modules within in the flow test, so we can compare them against the values generated from the API.
To help demonstrate these ideas better, here is a flow test I did for testing my cache api (added some extra comments to explain better):
<?php
class HobisTest_Api_Flow_CacheTest extends PHPUnit_Framework_TestCase
{
// Setting some constants so it's easier to construct known goods
const TEST_EXPIRY = 30;
const TEST_KEY_PREFIX = 'test';
const TEST_VALUE = 'brown chicken, brown cow';
//-----
// Support methods
//-----
protected $object;
protected $randomNumber;
// Here we generate a known good key, this allows us to test that the api internal workings generate what we expect
protected function getKnownGoodKey()
{
return self::TEST_KEY_PREFIX . Hobis_Api_Cache_Key::SEPARATOR . $this->getRandomNumber() . Hobis_Api_Cache_Key::SEPARATOR . '1';
}
protected function getObject()
{
return $this->object;
}
protected function getRandomNumber()
{
return $this->randomNumber;
}
//-----
//-----
// Setup and teardown
//-----
// You will want to add setup and teardown functions to your test classes
// These allow you to reference items for EVERY test within the current class
// While ensuring they are not carried over from one test to the other
// Basically a clean slate for every test
public function setUp()
{
$this->object = $this->getMock('Hobis_PhpUnit_DefaultTestObject');
$this->randomNumber = mt_rand();
}
public function tearDown()
{
unset(
$this->object,
$this->randomNumber
);
}
//-----
//-----
// Test methods
//-----
// The actual test method
public function testCache()
{
// Configure object
// Setting up so any references to $this->getId() will return 1
// If you look in the getKnownGoodKey() it is constructed with 1 as well
$this->object->expects($this->any())->method('getId')->will($this->returnValue(1));
// So now I am calling on my API to generate a cache key based on
// values used here, and when I constructed my "known good" key
$key = Hobis_Api_Cache_Key_Package::factory(
array(
'dynamicSuffixes' => array($this->getRandomNumber(), $this->getObject()->getId()),
'expiry' => self::TEST_EXPIRY,
'staticPrefix' => self::TEST_KEY_PREFIX,
'value' => self::TEST_VALUE
)
);
// Calling set via api
$setStatus = Hobis_Api_Cache_Package::set($key);
// Check that call was what we expect
$this->assertTrue($setStatus);
// Now let's retrieve the cached value so we can test if it's available
$cachedValue = Hobis_Api_Cache_Package::get($key);
// Test the attributes against "known good" values
$this->assertSame($key->getKey(), $this->getKnownGoodKey());
$this->assertSame($cachedValue, self::TEST_VALUE);
}
//-----
}
If a function is hard to test, it is a code smell. What is making it difficult to test and can it feasibly be changed to make that easier.
In your case, it seems to me that you function is doing too many things. You are checking if the simulation is complete, getting the batter and the pitcher, and simulating the at-bat. When you are describing if what the function does and you use the word 'AND', break up the functionality.
You are also suffering from a lack of dependency injection, so you can't pass in the mock objects ($batter and pitcher).
You also want to avoid using new in your functions (except if it is part of a factory) You can't replace that object and are dependent on the functionality that the class has. You are now unable to control what that object does.
Update
RE: your comment about the advanceInning and isComplete being moved to someObject. Think about things in terms of behavior. Don't just put a function into an object just because. I would have a Game object that would have isComplete and playNextInning as the public methods. What objects you are going to have all depend on your abstractions and what you are trying to achieve. Your objects should represent and be responsible for one thing. You have a game which represents the game. Each game has an inning, so you will probably have an inning object. You have two teams, so you will likely have a team object. You may want to have an inning factory that will create innings for you, that you pass into the game constructor (then you can mock it when you do testing). Depending on the logic that you end up with, you may even abstract the half innings into objects. That will all be determined by the behavior that you are trying to achieve.
You will find that you end up with ton of really small objects which is a GOOD THING. As your design will be flexible and more extensible.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
Before I begin:
My question was put on hold as primarily opinion-based. But I've done my best to reedit it in a more precise way again. In the hope, that its content will support its reopening.
So here is my question again:
It's about my HMVC project, a PHP framework, in which the M, V & C components are encapsulated in "independent" blocks (module directories). The project should not contain any static class members, static methods, singletons or service locators. I am using a dependency injection container, therefore beeing able to provide inversion of control (IoC).
In a class AbstractTemplate I assign the needed root paths of the template files as default values to the parameters of the class constructor:
abstract class AbstractTemplate {
public function __construct(
, $appLayoutsPath = '[app-root-path]/Layouts/Default'
, $moduleLayoutsPath = '[module-root-path]/Templates/Layouts'
, $moduleTemplatesPath = '[module-root-path]/Templates/Templates'
) {
//...
}
}
But in this way I couple the class to a hard-coded representation of the file system.
Therefore I considered passing the default values by using a separate class, which in turn holds the required values as class constants:
class Constants {
const APP_LAYOUTS_PATH = '[app-root-path]/Layouts/Default';
const MODULE_LAYOUTS_PATH = '[module-root-path]/Templates/Layouts';
const MODULE_TEMPLATES_PATH = '[module-root-path]/Templates/Templates';
}
abstract class AbstractTemplate {
public function __construct(
, $appLayoutsPath = Constants::APP_LAYOUTS_PATH
, $moduleLayoutsPath = Constants::MODULE_LAYOUTS_PATH
, $moduleTemplatesPath = Constants::MODULE_TEMPLATES_PATH
) {
//...
}
}
This way I couple the abstract class to the concrete implementation Constants.
I'd like to ask you:
Can the second option be tested without problems?
Is there another concrete possibility to provide default values and in the mean time to preserve a good testability?
I appreciate your answers and thank you for your time.
You can argue for both and you will not be worng since it is just an example detatched from any "real" code. But in my opinion this should be your starting code:
abstract class AbstractTemplate {
const DEFAULT_APP_LAYOUTS_PATH = '[app-root-path]/Layouts/Default';
const DEFAULT_MODULE_LAYOUTS_PATH = '[module-root-path]/Templates/Layouts';
const DEFAULT_MODULE_TEMPLATES_PATH = '[module-root-path]/Templates/Templates';
public function __construct(
$appLayoutsPath = AbstractTemplate::DEFAULT_APP_LAYOUTS_PATH,
$moduleLayoutsPath = AbstractTemplate::DEFAULT_MODULE_LAYOUTS_PATH,
$moduleTemplatesPath = AbstractTemplate::DEFAULT_MODULE_TEMPLATES_PATH
) {
//...
}
}
So you have your constants and you may reuse it (hopefully in the same class or in whatever class makes it "real", and not outside of it!)
You could argue that "class Constants" would be better if you are going to reuse the constants from it in many different classes. The problem with that approach is that it goes against very basic OOP principles. That is: You should have just one object that does sth for you with theese pathes. And if you need different things to be done you just reuse this one object in many different objects in many different ways...
Also Unit Testing or Dependency Injection and Inversion of Controll does not change anything here. But if you are providing code that you "know" that will only be used with IoC, you could argue if having any defaults is good idea at all and if it would not be better to inject everything from container...
I will probably go with option #2. I like to separate things out (using Separation of Concerns principles), and code reuse (Don't Repeat Yourself principle). It wasn't immediately clear to me from the question if you intend to reuse the default values in multiple classes or not. If you do, Option #2 is even better, since you have to change the actual string default values only in one place.
Not really. You are in a way creating a type that has default parameters. Imagine your Constants class is a type of int. Is there a real issue that your class depends on an integer type? Sometimes you have to have some variables in your class, and Constants is one of those variables.
Your class will always depend on Constants, so you won't be able to easily swap in&out different constants. That can be an issue if you want to have a different set of constants for i.e. testing, or another environment (development, production, testing, etc)
Personally I think I'd off-load the default values to a configuration text file, which can be different in different environments
Config file way
File called 'config/my-config.php';
/**
* Config for default
*/
return array(
'APP_LAYOUTS_PATH' => '[app-root-path]/Layouts/Default'
);
In your application:
$config = require 'config/my-config.php';
echo $config['APP_LAYOUTS_PATH']; //'[app-root-path]/Layouts/Default';
If-then-else way (can be combined with config files)
if ($mySpecificCondition)
$appLayoutsPath = '[app-root-path]/Layouts/Default';
else
$appLayoutsPath = '[app-root-path]/Layouts/NonDefault';
Or
switch ($mySpecificCondition)
{
case 'prod':
$configFile= 'config_path/production.config.php';
break;
case 'devel':
$configFile= 'config_path/development.config.php';
break;
case 'test':
$configFile= 'config_path/test.config.php';
break;
}
$config = require $configFile;
To clarify you may have a situation where you have the same file name with different contents on different environments. Or you may wish to have different parameters based on a condition. The above gives some ideas.
In my case I use both methods for different things. i.e. I have the same file name with different contents for email/IP configuration for prod/development. But for something like operating system default font file folder placement, I use if/then/else. if (OS == WIN) $path = X; else $path = Y;
Also remember to use Keep It Simple principle. You can always refactor your design later. Think about how your design will play out in the future, of course, but don't make it overly-complicated until you have to.
Clean Code
I fully agree with George Dryser in that option 2 is cleaner. I don't quite agree with him on his second point though:
I'd strongly recommend not to avoid entire functionality such as static class members purely for design or stylistic considerations, it's there for a reason.
The language features exist, but that doesn't necessarily mean that they should be used for this particular purpose. Also, the question isn't as much about style as much as it is about (de-)coupling.
Interdependence
To address your 3rd point:
... class Constants is introducing this interdependence/coupling ...
There's no interdependence here, since AbstractTemplate depends on Constants, but Constants has no dependencies. Your 2nd option can be tested, but it's not very flexible.
Coupling
In your 2nd point you say:
Is there a real issue, that each class using option 2 will depend on a Constants class?
The issue isn't that there's a dependency being introduced, but what kind of dependency. Reading values from a specific, named member of the application is tight coupling, which you should try to avoid. Instead, make the default values constant only to those classes that read the values:
How objects that implement IDefaultsProvider get their values does not concern the AbstractTemplate class at all.
Possible Solution
For the sake of being thorough, I'm going to reinvent the wheel here.
In PHP, the interface for IDefaultsProvider can be written like this:
interface IDefaultsProvider {
/** Returns the value of a variable identified by `$name`. */
public function read($name);
}
The interface is a contract that says: "When you have an object that implements IDefaultsProvider, you can read default values using its read() method and it will return the default value you requested".
I'll get to specific implementations of the interface further below. First, let's see how the code for AbstractTemplate might look like:
abstract class AbstractTemplate {
private static function getDefaultsProvider() {
// Let "someone else" decide what object to use as the provider.
// Not `AbstractTemplate`'s job.
return Defaults::getProvider();
}
private static function readDefaultValue($name) {
return static::getDefaultsProvider()->read($name);
}
public function __construct(
, $appLayoutsPath = static::readDefaultValue('app_layouts_path')
, $moduleLayoutsPath = static::readDefaultValue('module_layouts_path')
, $moduleTemplatesPath = static::readDefaultValue('module_templates_path')
) {
//...
}
}
We've gotten rid of Constants and its members (const APP_LAYOUTS_PATH etc). AbstractTemplate is now blissfully ignorant of where the default values come from. Now, AbstractTemplate and the default values are loosely coupled.
The implementation of AbstractTemplate only knows is how to get a IDefaultsProvider object (see method getDefaultsProvider()). In my example, I'm using the following class for that:
class Defaults {
/** #var IDefaultsProvider $provider */
private $provider;
/** #returns IDefaultsProvider */
public static function getProvider() {
return static::$provider;
}
/**
* Changes the defaults provider instance that is returned by `getProvider()`.
*/
public static function useInstance(IDefaultsProvider $instance) {
static::$instance = $instance;
}
}
At this point, the reading part is complete, since AbstractTemplate can get a defaults provider using Defaults::getProvider(). Let's look at bootstrapping next. This is where we can start to address different scenarios like testing, development and production.
For testing, we might have a file called bootstrap.test.php that's included only when tests are being run. It needs to be included before AbstractTemplate, of course:
<?php
// bootsrap.test.php
include_once('Defaults.php');
include_once('TestingDefaultsProvider.php');
Defaults::useInstance(new TestingDefaultsProvider());
The other scenarios require their own bootstrapping as well.
<?php
// bootsrap.production.php
include_once('Defaults.php');
include_once('ProductionDefaultsProvider.php');
Defaults::useInstance(new ProductionDefaultsProvider());
... and so on.
What remains to be done are the implementations of IDefaultProvider. Let's start with TestingDefaultsProvider:
class TestingDefaultsProvider implements IDefaultsProvider {
public function read($name) {
return $this->values[$name];
}
private $values = [
'app_layouts_path' => '[app-root-path]/Layouts/Default',
'module_layouts_path' => '[module-root-path]/Templates/Layouts',
'module_templates_path' => '[module-root-path]/Templates/Templates',
// ... more defaults ...
];
}
It might actually be as simple as that.
Let's assume that, in production, we want the configuration data to reside in a configuration file:
// defaults.json
{
"app_layouts_path": "[app-root-path]/Layouts/Default",
"module_layouts_path": "[module-root-path]/Templates/Layouts",
"module_templates_path": "[module-root-path]/Templates/Templates",
// ... more defaults ...
}
In order to get to the defaults in the file, all we need to do is read it once, parse the JSON data and return the default values when requested. For the sake of this example, I'm gonna go with lazy reading & parsing.
class ProductionDefaultsProvider implements IDefaultsProvider {
public function read($name) {
$parsedContent = $this->getAllDefaults();
return $parsedContent[$name];
}
private static $parsedContent = NULL;
private static function getAllDefaults() {
// only read & parse file content once:
if (static::$parsedContent == NULL) {
static::$parsedContent = static::readAndParseDefaults();
}
return static::$parsedContent;
}
private static readAndParseDefaults() {
// just an example path:
$content = file_get_contents('./config/defaults.json');
return json_decode($content, true);
}
}
Here's the whole shebang:
Conclusion
Is there a better alternative to provide default values?
Yes, provided that it's worth the effort. The key principle is inversion of control (also IoC). The purpose of my example was to show how IoC can be implemented. You can apply IoC to configuration data, complex object dependencies or, in your case, defaults.
If you only have a few default values in your application, it might be overkill to invert control. If there's plenty of default values in your application or if you cannot expect the number of defaults, configuration variables, etc to stay very low in the future though, you might want to look into dependency injection.
Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.
— Martin Fowler
Also, this:
Basically, instead of having your objects creating a dependency or asking a factory object to make one for them, you pass the needed dependencies in to the object externally, and you make it somebody else's problem.
— SO Answer to "What is Dependency Injection?" by wds
The good news is that there are plenty of DI frameworks around:
Zend DI
Symfony DI
PHP-DI
Ray-DI
...
Option 2 is much cleaner and easier maintainable code example I would go with 2, code-hinting applications like phpStorm or DW will understand option 2 better.
I'd strongly recommend not to avoid entire functionality such as static class members purely for design or stylistic considerations, it's there for a reason.
I'm using __get() to make some of my properties "dynamic" (initialize them only when requested). These "fake" properties are stored inside a private array property, which I'm checking inside __get.
Anyway, do you think it's better idea to create methods for each of these proprties instead of doing it in a switch statement?
Edit: Speed tests
I'm only concerned about performance, other stuff that #Gordon mentioned are not that important to me:
unneeded added complexity - it doesn't really increase my app complexity
fragile non-obvious API - I specifically want my API to be "isolated"; The documentation should tell others how to use it :P
So here are the tests that I made, which make me think that the performance hit agument is unjustified:
Results for 50.000 calls (on PHP 5.3.9):
(t1 = magic with switch, t2 = getter, t3 = magic with further getter call)
Not sure what the "Cum" thing mean on t3. It cant be cumulative time because t2 should have 2K then...
The code:
class B{}
class A{
protected
$props = array(
'test_obj' => false,
);
// magic
function __get($name){
if(isset($this->props[$name])){
switch($name){
case 'test_obj':
if(!($this->props[$name] instanceof B))
$this->props[$name] = new B;
break;
}
return $this->props[$name];
}
trigger_error('property doesnt exist');
}
// standard getter
public function getTestObj(){
if(!($this->props['test_obj'] instanceof B))
$this->props['test_obj'] = new B;
return $this->props['test_obj'];
}
}
class AA extends A{
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name); // give me a break, its just a test :P
if(method_exists($this, $getter))
return $this->$getter();
trigger_error('property doesnt exist');
}
}
function t1(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
function t2(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->getTestObj();
}
echo 'done.';
}
function t3(){
$obj = new AA;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
t1();
t2();
t3();
ps: why do I want to use __get() over standard getter methods? the only reason is the api beauty; because i don't see any real disadvantages, I guess it's worth it :P
Edit: More Speed tests
This time I used microtime to measure some averages:
PHP 5.2.4 and 5.3.0 (similar results):
t1 - 0.12s
t2 - 0.08s
t3 - 0.24s
PHP 5.3.9, with xdebug active this is why it's so slow:
t1 - 1.34s
t2 - 1.26s
t3- 5.06s
PHP 5.3.9 with xdebug disabled:
t1 - 0.30
t2 - 0.25
t3 - 0.86
Another method:
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name);
if(method_exists($this, $getter)){
$this->$name = $this->$getter(); // <-- create it
return $this->$name;
}
trigger_error('property doesnt exist');
}
A public property with the requested name will be created dynamically after the first __get call. This solves speed issues - getting 0.1s in PHP 5.3 (it's 12 times faster then standard getter), and the extensibility issue raised by Gordon. You can simply override the getter in the child class.
The disadvantage is that the property becomes writable :(
Here is the results of your code as reported by Zend Debugger with PHP 5.3.6 on my Win7 machine:
As you can see, the calls to your __get methods are a good deal (3-4 times) slower than the regular calls. We are still dealing with less than 1s for 50k calls in total, so it is negligible when used on a small scale. However, if your intention is to build your entire code around magic methods, you will want to profile the final application to see if it's still negligible.
So much for the rather uninteresting performance aspect. Now let's take a look at what you consider "not that important". I'm going to stress that because it actually is much more important than the performance aspect.
Regarding Uneeded Added Complexity you write
it doesn't really increase my app complexity
Of course it does. You can easily spot it by looking at the nesting depth of your code. Good code stays to the left. Your if/switch/case/if is four levels deep. This means there is more possible execution pathes and that will lead to a higher Cyclomatic Complexity, which means harder to maintain and understand.
Here is numbers for your class A (w\out the regular Getter. Output is shortened from PHPLoc):
Lines of Code (LOC): 19
Cyclomatic Complexity / Lines of Code: 0.16
Average Method Length (NCLOC): 18
Cyclomatic Complexity / Number of Methods: 4.00
A value of 4.00 means this is already at the edge to moderate complexity. This number increases by 2 for every additional case you put into your switch. In addition, it will turn your code into a procedural mess because all the logic is inside the switch/case instead of dividing it into discrete units, e.g. single Getters.
A Getter, even a lazy loading one, does not need to be moderately complex. Consider the same class with a plain old PHP Getter:
class Foo
{
protected $bar;
public function getBar()
{
// Lazy Initialization
if ($this->bar === null) {
$this->bar = new Bar;
}
return $this->bar;
}
}
Running PHPLoc on this will give you a much better Cyclomatic Complexity
Lines of Code (LOC): 11
Cyclomatic Complexity / Lines of Code: 0.09
Cyclomatic Complexity / Number of Methods: 2.00
And this will stay at 2 for every additional plain old Getter you add.
Also, take into account that when you want to use subtypes of your variant, you will have to overload __get and copy and paste the entire switch/case block to make changes, while with a plain old Getter you simply overload the Getters you need to change.
Yes, it's more typing work to add all the Getters, but it is also much simpler and will eventually lead to more maintainable code and also has the benefit of providing you with an explicit API, which leads us to your other statement
I specifically want my API to be "isolated"; The documentation should tell others how to use it :P
I don't know what you mean by "isolated" but if your API cannot express what it does, it is poor code. If I have to read your documentation because your API does not tell me how I can interface with it by looking at it, you are doing it wrong. You are obfuscating the code. Declaring properties in an array instead of declaring them at the class level (where they belong) forces you to write documentation for it, which is additional and superfluous work. Good code is easy to read and self documenting. Consider buying Robert Martin's book "Clean Code".
With that said, when you say
the only reason is the api beauty;
then I say: then don't use __get because it will have the opposite effect. It will make the API ugly. Magic is complicated and non-obvious and that's exactly what leads to those WTF moments:
To come to an end now:
i don't see any real disadvantages, I guess it's worth it
You hopefully see them now. It's not worth it.
For additional approaches to Lazy Loading, see the various Lazy Loading patterns from Martin Fowler's PoEAA:
There are four main varieties of lazy load. Lazy Initialization uses a special marker value (usually null) to indicate a field isn't loaded. Every access to the field checks the field for the marker value and if unloaded, loads it. Virtual Proxy is an object with the same interface as the real object. The first time one of its methods are called it loads the real the object and then delegates. Value Holder is an object with a getValue method. Clients call getValue to get the real object, the first call triggers the load. A ghost is the real object without any data. The first time you call a method the ghost loads the full data into its fields.
These approaches vary somewhat subtly and have various trade-offs. You can also use combination approaches. The book contains the full discussion and examples.
If your capitalization of the class names and the key names in $prop matched, you could do this:
class Dummy {
private $props = array(
'Someobject' => false,
//etc...
);
function __get($name){
if(isset($this->props[$name])){
if(!($this->props[$name] instanceof $name)) {
$this->props[$name] = new $name();
}
return $this->props[$name];
}
//trigger_error('property doesnt exist');
//Make exceptions, not war
throw new Exception('Property doesn\'t exist');
}
}
And even if the capitalization didn't match, as long as it followed the same pattern it could work. If the first letter was always capitalized you could use ucfirst() to get the class name.
EDIT
It's probably just better to use plain methods. Having a switch inside a getter, especially when the code executed for each thing you try to get is different, practically defeats the purpose of the getter, to save you from having to repeat code. Take the simple approach:
class Something {
private $props = array('Someobject' => false);
public getSomeobject() {
if(!($this->props['Someobject'] instanceof Someobject)) {
//Instantiate and do extra stuff
}
return $this->props['Someobject'];
}
public getSomeOtherObject() {
//etc..
}
}
I'm using __get() to make some of my properties "dynamic" (initialize them only when requested). These "fake" properties are stored inside a private array property, which I'm checking inside __get.
Anyway, do you think it's better idea to create methods for each of these proprties instead of doing it in a switch statement?
The way you ask your question I don't think it is actually about what anybody thinks. To talk about thoughts, first of all it must be clear which problem you want to solve here.
Both the magic _get as well as common getter methods help to provide the value. However, what you can not do in PHP is to create a read-only property.
If you need to have a read-only property, you can only do that with the magic _get function in PHP so far (the alternative is in a RFC).
If you are okay with accessor methods, and you are concerned about typing methods' code, use a better IDE that does that for you if you are really concerned about that writing aspect.
If those properties just do not need to be concrete, you can keep them dynamic because a more concrete interface would be a useless detail and only make your code more complex than it needs to be and therefore violates common OO design principles.
However, dynamic or magic can also be a sign that you do something wrong. And also hard to debug. So you really should know what you are doing. That needs that you make the problem you would like to solve more concrete because this heavily depends on the type of objects.
And speed is something you should not test isolated, it does not give you good suggestions. Speed in your question sounds more like a drug ;) but taking that drug won't give you the power to decide wisely.
Using __get() is said to be a performance hit. Therefore, if your list of parameters is static/fixed and not terribly long, it would be better performance-wise to make methods for each and skip __get(). For example:
public function someobject() {
if(!($this->props[$name] instanceof Someobject))
$this->props[$name] = new Someobject;
// do stuff to initialize someobject
}
if (count($argv = func_get_args())) {
// do stuff to SET someobject from $a[0]
}
return $this->props['someobject'];
}
To avoid the magic methods, you'd have to alter the way you use it like this
$bar = $foo->someobject; // this won't work without __get()
$bar = $foo->someobject(); // use this instead
$foo->someobject($bar); // this is how you would set without __set()
EDIT
Edit, as Alex pointed out, the performance hit is millisecond small. You can try both ways and do some benchmarks, or just go with __get since it's not likely to have a significant impact on your application.
I'm having a problem with a line of code like:
$user->has('roles', ORM::factory('role', array('name' => 'unverified')))
I can mock the first argument, but can only assert that the 2nd argument returns a class. In some classes I make multiple uses of has and need to be able to test them properly. To be clear, I need to confirm that "unverified" was passed into the factory method of the 2nd argument. Any help is much appreciated.
The class I'm testing:
<?php
/**
* Policy class to determine if a user can upload a file.
*/
class Policy_File_Upload extends Policy
{
const NOT_LOGGED_IN = 1;
const NOT_VERIFIED = 2;
public function execute(Model_ACL_User $user, array $extra = NULL)
{
if ($user->can('login'))
{
return self::NOT_LOGGED_IN;
}
elseif ($user->has('roles', ORM::factory('role', array('name' => 'unverified'))))
{
return self::NOT_VERIFIED;
}
return TRUE;
}
}
and the corresponding test:
public function test_guest()
{
// User mock
$user = $this->getMock('Model_User', array('can', 'has'), array(), '', FALSE);
$user->expects($this->any())->method('can')->with('login')->will($this->returnValue(TRUE));
$user->expects($this->any())->method('has')->with('roles', $this->logicalOr
(
))
->will($this->returnCallback(array($this, 'roles')));
$policy = new Policy_File_Upload;
$this->assertSame(Policy_File_Upload::NOT_VERIFIED, $policy->execute($user));
}
You can always go the data-driven route of preparing test data for each case and verify the result of calling the function. In the end, you don't so much care that 'unverified' gets passed to ORM::factory() but rather that the correct result comes out of execute() based on the input.
Testing the implementation details makes the test brittle and difficult to write. If you can test the results instead, your tests won't break when you change how you arrive at the result. It may take longer to put together a data set for all your use cases, but it can generally be shared among tests.
To be clear, I need to confirm that "unverified" was passed into the factory method of the 2nd argument.
<?php
public function execute(Model_ACL_User $user, array $extra = NULL)
[...] ORM::factory('role', array('name' => 'unverified')) [...]
I'm sorry mate, you can't do that as there is no (sane) way to mock out a static method call.
The argument to why this is a problem are similar to one of Sebastian Bergmanns blog post: Testing-Code-That-Uses-Singletons
There are options like runkit that you could choose to replace the "ORM" class at runtime with a mocked version but thats really painfull.
So there are a couple of options:
You could create something like a Policy_File_Upload_Data_Provider that has a ->getRoles method where you put your ORM access. That would allow you to test your business logic nicely and testing that data access class should be a little easier as it doesn't to that much (just accessing the orm).
You could Inject your ORM class (or if that doesn't work out maybe just its name).
Depending on the class its self you should be able to create an instance and call ->factory like it would be a normal method. You could mock that.
If you don't want that just leaving that in there is also a not SO bad option.
Hope that at least gave you an idea/overview.
Additional Links why it's hard to test statics:
Misko Hevery - Flaw: Brittle Global State & Singletons
Kore Nordmann - Static considered harmful
You can actually do verification on parameters passed to mock methods utilizing parameter capturing in the Phake mocking framework for PHP.
public function test_guest()
{
// User mock
$user = Phake::mock('Model_User');
when($user)->can('login')->thenReturn(FALSE);
when($user)->has('roles', $this->anything())->thenGetReturnByLambda(array($this, 'roles'));
$policy = new Policy_File_Upload;
$this->assertSame(Policy_File_Upload::NOT_VERIFIED, $policy->execute($user));
Phake::verify($user)->has('roles', Phake::capture($factoriedRole));
$this->assertEquals('unverified', $factoriedRole->get('name'));
}
This example is assuming that you have the ability to check the name on $factoriedRole, obviously that piece needs to be changed depending on how that ORM stack works.
A small note, I agree with edorian regarding statics. If possible I would always prefer redesigning your code to not require statics, but sometimes that isn't possible, in which case this is a workable solution.
Phake Github Page
Phake Documentation on Parameter Capturing
Why is testing singletons or registry pattern hard in a language like PHP which is request driven?
You can write and run tests aside from the actual program execution, so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.
Am I missing something?
While it's true that "you can write and run tests aside of the actual program execution so that you are free to affect the global state of the program and run some tear downs and initialization per each test function to get it to the same state for each test.", it is tedious to do so. You want to test the TestSubject in isolation and not spend time recreating a working environment.
Example
class MyTestSubject
{
protected $registry;
public function __construct()
{
$this->registry = Registry::getInstance();
}
public function foo($id)
{
return $this->doSomethingWithResults(
$registry->get('MyActiveRecord')->findById($id)
);
}
}
To get this working you have to have the concrete Registry. It's hardcoded, and it's a Singleton. The latter means to prevent any side-effects from a previous test. It has to be reset for each test you will run on MyTestSubject. You could add a Registry::reset() method and call that in setup(), but adding a method just for being able to test seems ugly. Let's assume you need this method anyway, so you end up with
public function setup()
{
Registry::reset();
$this->testSubject = new MyTestSubject;
}
Now you still don't have the 'MyActiveRecord' object it is supposed to return in foo. Because you like Registry, your MyActiveRecord actually looks like this
class MyActiveRecord
{
protected $db;
public function __construct()
{
$registry = Registry::getInstance();
$this->db = $registry->get('db');
}
public function findById($id) { … }
}
There is another call to Registry in the constructor of MyActiveRecord. You test has to make sure it contains something, otherwise the test will fail. Of course, our database class is a Singleton as well and needs to be reset between tests. Doh!
public function setup()
{
Registry::reset();
Db::reset();
Registry::set('db', Db::getInstance('host', 'user', 'pass', 'db'));
Registry::set('MyActiveRecord', new MyActiveRecord);
$this->testSubject = new MyTestSubject;
}
So with those finally set up, you can do your test
public function testFooDoesSomethingToQueryResults()
{
$this->assertSame('expectedResult', $this->testSubject->findById(1));
}
and realize you have yet another dependency: your physical test database wasn't setup yet. While you were setting up the test database and filled it with data, your boss came along and told you that you are going SOA now and all these database calls have to be replaced with Web service calls.
There is a new class MyWebService for that, and you have to make MyActiveRecord use that instead. Great, just what you needed. Now you have to change all the tests that use the database. Dammit, you think. All that crap just to make sure that doSomethingWithResults works as expected? MyTestSubject doesn't really care where the data comes from.
Introducing mocks
The good news is, you can indeed replace all the dependencies by stubbing or mock them. A test double will pretend to be the real thing.
$mock = $this->getMock('MyWebservice');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
This will create a double for a Web service that expects to be called once during the test with the first argument to method findById being 1. It will return predefined data.
After you put that in a method in your TestCase, your setup becomes
public function setup()
{
Registry::reset();
Registry::set('MyWebservice', $this->getWebserviceMock());
$this->testSubject = new MyTestSubject;
}
Great. You no longer have to bother about setting up a real environment now. Well, except for the Registry. How about mocking that too. But how to do that. It's hardcoded so there is no way to replace at test runtime. Crap!
But wait a second, didn't we just say MyTestClass doesn't care where the data comes from? Yes, it just cares that it can call the findById method. You hopefully think now: why is the Registry in there at all? And right you are. Let's change the whole thing to
class MyTestSubject
{
protected $finder;
public function __construct(Finder $finder)
{
$this->finder = $finder;
}
public function foo($id)
{
return $this->doSomethingWithResults(
$this->finder->findById($id)
);
}
}
Byebye Registry. We are now injecting the dependency MyWebSe… err… Finder?! Yeah. We just care about the method findById, so we are using an interface now
interface Finder
{
public function findById($id);
}
Don't forget to change the mock accordingly
$mock = $this->getMock('Finder');
$mock->expects($this->once())
->method('findById')
->with($this->equalTo(1))
->will($this->returnValue('Expected Unprocessed Data'));
and setup() becomes
public function setup()
{
$this->testSubject = new MyTestSubject($this->getFinderMock());
}
Voila! Nice and easy and. We can concentrate on testing MyTestClass now.
While you were doing that, your boss called again and said he wants you to switch back to a database because SOA is really just a buzzword used by overpriced consultants to make you feel enterprisey. This time you don't worry though, because you don't have to change your tests again. They no longer depend on the environment.
Of course, you still you have to make sure that both MyWebservice and MyActiveRecord implement the Finder interface for your actual code, but since we assumed them to already have these methods, it's just a matter of slapping implements Finder on the class.
And that's it. Hope that helped.
Additional Resources:
You can find additional information about other drawbacks when testing Singletons and dealing with global state in
Testing Code That Uses Singletons
This should be of most interest, because it is by the author of PHPUnit and explains the difficulties with actual examples in PHPUnit.
Also of interest are:
TotT: Using Dependency Injection to Avoid Singletons
Singletons are Pathological Liars
Flaw: Brittle Global State & Singletons
Singletons (in all OOP languages, not just PHP) make a particular kind of debugging called unit testing difficult for the same reason that global variables do. They introduce global state into a program, meaning that you can't test any modules of your software that depend on the singleton in isolation. Unit testing should include only the code under test (and its superclasses).
Singletons are essentially global state, and while having global state can make sense in certain circumstances, it should be avoided unless it's necessary.
When finishing a PHP test, you can flush singleton instance like this:
protected function tearDown()
{
$reflection = new ReflectionClass('MySingleton');
$property = $reflection->getProperty("_instance");
$property->setAccessible(true);
$property->setValue(null);
}
Or in more specific words, is it "ok" to not be relying on setters and getters?
I'm dealing with a class that checks the availability of rooms and sets public properties of which there are more than a dozen. Things such as:
unitNumber
roomTypes ( array )
codeCorporate
codeGroup
numberKids
numberAdults
numberRooms
currency
minRate
maxRate
soapServer
units ( array )
hotelId
And after an object is instantiated those properties are set with $this-> inside various methods. However the code that deals with the object often sets public properties directly instead of using getter/setter methods:
$object->something = 3;
foreach ($object->things as $thing ) { }
If I have the time to refactor this class..
Should I stick all of these properties in a data array that's a private property, and define __set and __get methods?
Should I make a single getter method for each of the properties?
In my opinion, it is rarely a good idea to have any public members. It increases coupling between classes, and makes refactoring very complicated (should you need it.)
Setters/Getters are the way to go, and the very small performance penalty that you pay for it is usually either optimized away, or trumped by elegance.
To answer your question about array vs. single-getter-per-var, it's a matter of taste. I tend to only keep variables of a similar type within an array, and separate the rest.
I personally have yet to find a truly good reason for a public property, though im open for suggestion :-)
Although i much prefer specified getters/setters for each property (whether that's a proxy to a generalized get($name) or not). I assume you have other code already that uses direct assignment so in that case i would say to proceed with using the magic __get/__set methods.
I think most people will recommend using setters & getters. Right now you're limited to simply setting & fetching the property, but what if you want to log when that property is accessed? Or perhaps you want to run the value by a validation function first (email, phonenumber, zip code, etc). Maybe you'll need to call another function, or set another property. I think you see where I'm heading with this. By using setters & getters, you add a valuable layer of encapsulation to your classes, and 99% of the time this is worth the extra typing you'll need to do ;) Imagine trying to do the examples above without setters & getters. It'd be a big headache to say the least.
Edit: I forgot to mention Doctrine. It's an object relation mapper (ORM) that can automatically setup setters & getters for you (amongst other things). You can check it out at http://www.doctrine-project.org/
I would take a step back and ask some more general questions:
Why am I having to expose this much information; what is using it and why?
Is this class really just a data structure without behavior, in which case should be a private class to some other class?
Does this class serve a single purpose, or is it on the path to becoming monolithic?
You may discover that you are able to create views of an instance of a class to export to a database, display in a form, etc. Check out the "Builder" and "Acyclic Visitor" patterns to start with.
Regarding accessors, I do not see a need to use them for what you are describing: retrieving class properties and internal state information, aka a struct. However, for attributes of a class I could see the benefit in certain cases, but more for retrieving attributes, not for mutations of your object's state.
If I may add my grain of salt several months later :
It is very un-OO to have public properties. Everything should be encapsulated, simply because (among other reasons) using direct attribute manipulation doesn't give you ways to easily refactor or perform (more) control checks when some external source modifies the field. For example, let's say you have a class with many fields that is used throughout a project several times, and that project contains several thousands of files; it's a project that has been running and expanded for a few years now. Let's say that the company is changing it's business model, or that a problem is found with some of the field's data type and now is required to have some validation; will you duplicate that validation in all those thousands of source code that is directly accessing the public member? In PHP, the solution may be simple, but not in most OO programming language (i.g. Java). The fact is that OO is based on encapsulation. In short, encapsulation doesn't only produce clean code, but also highly maintainable (not to say cost-effective and cohesive) code.
Your suggestion of having a private member (array) being manipulated by __get / __set is good. This way, if you need some extra validation along the road, simply create your setter and/or your getter and it will be the end of it. Some may argue with that being counter productive as the code completion cannot kick-in on __get / __set. IMHO, relying on code completion is simply lazy coding. But then again, having every member have it's own getter and/or setter allows you to write a more comprehensive API documentation. Personally, I usually use that technique for internal or very general purpose classes. If all your fields do not require any validation, or there are as you said several dozen of them, then using magic methods would be acceptable, in my opinion.
The bottom line is to avoid direct member access on class instances, period. How you decide to achieve this is strictly up to you. Just make sure that the API is well documented the more abstract you make it.
On a final note, in PHP, if you already have classes that are being used that are not encapsulating their fields, for example something like
class SomeObject {
public $foo;
public $bar;
public $baz;
//...
}
you can simply fix this class without having to refactor anything with something like :
class SomeObject {
private $_foo; // having underscore as prefix helps to know what's private/protected
private $_bar; // inside the code.
private $_baz;
public function __get($name) {
$methodName = 'get'.ucfirst($name);
if (method_exists($this, $methodName)) {
return $this->{$methodName}();
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function __set($name, $value) {
$methodName = 'set'.ucfirst($name);
if (method_exists($this, $methodName)) {
$this->{$methodName}($value);
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function getFoo() { return $this->_foo; }
public function setFoo($value) { $this->_foo = $value; }
public function getBar() { return $this->_bar; }
public function setBar($value) { $this->_bar = $value; }
public function getBaz() { return $this->_baz; }
public function setBaz($value) { $this->_baz = $value; }
}
And then
$obj = new SomeObject();
$obj->foo = 'Hello world'; // legacy code support
$obj->setFoo('Hello world'); // same thing, but preferred
And you satisfy both the OO paradigm and having direct access to attributes of an instance. You could also have __call() check for prefix 'get' or 'set' and call __get() and __set() accordingly, but I would not go that far, though this would truly enable general purpose classes to access it's private members via ->member and ->getMember()/->setMember()