After mocking object there are missing functions? - php

Admittedly I am very new to working with Mock objects but have come across a strange behavior that I hope someone can explain to me.
I have two classes class A and class B. B extends A and looks something like this.
abstract class A {
private $property
public __constructor( $arg ) {
//sets and does constructor stuff
}
public function a() {
//does stuff
}
public function b() {
//does more stuff
}
public function c() {
//calls b and does stuff
}
}
class B extends A {
const MyCONST = //some literal
public __constructor() {
parent::__constructor( self::MyCONST );
}
}
Since my class A is abstract I am doing my testing on class B. When testing function c I need to stub function b so I have done the following in my test.
$objectUnderTest = $this->getMockBuilder( 'B' )
->setMethods( array( 'b' ) )
->getMock();
$objectUnderTest->expects( $this->once() )
->method( 'b' )
->will( $this->returnValue( 5 ) );
$result = $objectUnderTest->c();
//then some assertions
The problem I am running into is that when the following test code is executed PHPUnit it complains that it can not find method c of $objectUnderTest. Now from what I understand even if I had created the mock object incorrectly and function c had become a stub method as opposed to a mock method it would still be invokeable right? Some debugging to confirm what PHPUnit was telling me I outputted to the console the results of get_class_methods() on the mock object as well as on a normal instance of my class B. This is what it outputted for each.
//class B
array(
(int) 0 => '__construct',
(int) 1 => 'a',
(int) 2 => 'b',
(int) 3 => 'c'
)
//mocked B
array(
(int) 0 => '__clone',
(int) 1 => 'b',
(int) 2 => 'expects',
(int) 3 => 'staticExpects',
(int) 4 => '__phpunit_getInvocationMocker',
(int) 5 => '__phpunit_getStaticInvocationMocker',
(int) 6 => '__phpunit_hasMatchers',
(int) 7 => '__phpunit_verify',
(int) 8 => '__phpunit_cleanup'
)
Does anyone know what happened to my other methods for this class or explain this behavior?

I've faced the same problem while trying to run your code, so I included file with classes (A and B) to the test class. It helped me overcome this problem.

Related

Default values to static variables

Is it possible to use Traits for giving default values to static variables? Consider the following example.
trait Properties {
public static $properties = [];
}
class Base {
use Properties;
}
Base::$properties[0] = 'val1';
Base::$properties[1] = 'val2';
Base::$properties[2] = 'val3';
class Derived extends Base {
use Properties;
}
Derived::$properties[1] = 'changed value';
Derived::$properties[3] = 'new value';
var_dump(Base::$properties);
var_dump(Derived::$properties);
I would like the output to be something like
array (size=3)
0 => string 'val1' (length=4)
1 => string 'val2' (length=4)
2 => string 'val3' (length=4)
array (size=4)
0 => string 'val1' (length=4)
1 => string 'changed value' (length=13)
2 => string 'val3' (length=4)
3 => string 'new value' (length=9)
The example does not work, since Base and Properties define the same property ($properties) in the composition of Derived. If I remove the use Properties from Derived, the $properties variable is the same for both Base and Derived, and any changes applies to both classes. I hoped to get around this by including Properties in both classes. Are there any nice ways to achieve what I want? I don't have to use Traits, I just thought this could help.
I suggest a pretty straightforward object-oriented style.
It goes without traits, but with method-accessors in place of attribute-accessors:
class Base {
private static $properties;
public static function getProperties() {
if (!isset(self::$properties)) {
self::$properties = ['val1', 'val2', 'val3']; // use `array('val1', 'val2', 'val3')` with PHP<5.4
}
return self::$properties;
}
}
class Derived extends Base {
private static $properties; // has nothing to do with parent::$properties!
public static function getProperties() {
if (!isset(self::$properties)) {
self::$properties = parent::getProperties();
self::$properties[1] = 'changed value';
self::$properties[] = 'new value';
}
return self::$properties;
}
}
var_dump(Base::getProperties());
var_dump(Derived::getProperties());
Note that there's no risk of modifying internal arrays from outside with method-accessors, and that there's practically no performance impact of using methods with memoization.

Anonymous function returns class properties? PHP

I was reading a WordPress tutorial in which the author used something like this (I simplified it):
class WPObject {
public $ID;
public $title;
public $content;
public $status;
public function __construct($wp_post) {
$modifiers = [
'key' => function($k, $v) {
return (substr($k, 0, 5) === "post_") ? substr($k, 5) : $k;
}
];
}
}
The function is supposed to remove the post_ prefix from the wp queried object. The question I have is regarding the function I posted above. That anonymous function seems to return an object with with the properties. When I did a print_r on it I get...
Array
(
[key] => Closure Object
(
[this] => WPObject Object
(
[ID] =>
[title] =>
[content] =>
[status] =>
)
[parameter] => Array
(
[$k] =>
[$v] =>
)
)
)
I'm still learning about anonymous functions and was wondering how/why it does this? If you call an anonymous function from an object, does it create an instance of that object or something?
Also, sorry if I'm using incorrect terminology. Don't have anonymous functions, closures, lambda functions straightened out yet.
Not a new instance, it has a reference to the same object in which it is created since PHP 5.4 I believe. So the closure itself can call properties or methods on that class as if being in that class.
class foo {
public $bar = 'something';
function getClosure(){
return function(){
var_dump($this->bar);
};
}
}
$object = new foo();
$closure = $object->getClosure();
//let's inspect the object
var_dump($object);
//class foo#1 (1) {
// public $bar =>
// string(9) "something"
//}
//let's see what ->bar is
$closure();
//string(9) "something"
//let's change it to something else
$object->bar = 'somethingElse';
//closure clearly has the same object:
$closure();
//string(13) "somethingElse"
unset($object);
//no such object/variables anymore
var_dump($object);
//NULL (with a notice)
//but closure stills knows it as it has a reference
$closure();
//string(13) "somethingElse"

Modify PHP Object Property Name

In PHP is it possible to change an Objects property key/name? For example:
stdClass Object
(
[cpus] => 2
[created_at] => 2011-05-23T01:28:29-07:00
[memory] => 256
)
I wish to change the key created_at to created in the Object leaving an object that looks like:
stdClass Object
(
[cpus] => 2
[created] => 2011-05-23T01:28:29-07:00
[memory] => 256
)
$object->created = $object->created_at;
unset($object->created_at);
Something like an adapter class may be a more robust choice though, depending on where and how often this operation is necessary.
class PC {
public $cpus;
public $created;
public $memory;
public function __construct($obj) {
$this->cpus = $obj->cpu;
$this->created = $obj->created_at;
$this->memory = $obj->memory;
}
}
$object = new PC($object);
No, since the key is a reference to the value, and not a value itself.
You're best off copying the original, then removing it.
$obj->created = $obj->created_at;
unset(obj->created_at);
Its similar to #deceze adapter, but without the need to create an extra class
$object = (object) array(
'cpus' => $obj->cpus,
'created' => $obj->created_at,
'memory' => $obj->memory
);

Least sloppy way to enforce allowable values or ranges for class properties

Say hypothetically I have a class...
class Main {
$prop1 = 2;
$prop2 = 23;
...
$prop42 = "what";
function __construct($arg_array) {
foreach ($arg_array as $key => $val) {
$this->$key = $val;
}
}
}
Say I create and object...
$attributes = array("prop1"=>1, "prop2"=>35235, "prop3"=>"test");
$o = new Main($attributes);
Providing for default property values if not supplied by the user is obvious. But what if I want to enforce arbitrary limits on user supplied values for object properties? What if I want to enforce $prop1 to be of int, be no less than 1, and be no greater than 5. And, $prop42 to be of type string, no less than 'A', and no greater than 'Z'? For this purpose, what would be the cleanest way, keeping the script as short and sweet as possible, using any possible language feature or trick?
I'm stuck in __construct() checking supplied values against a rule array built like so...
$allowable = array(
"prop1" => array(
'type' => 'int',
'allowable_values' => array(
'min' => 1,
'max' => 5
)
),
"prop2" => array(
'type' => 'int',
'allowable_values' => array(
1,
235,
37,
392,
13,
409,
3216
)
),
...
"prop42" => array(
'type' => 'string',
'allowable_values' => array(
'min' => 'A',
'max' => 'Z'
)
)
);
As you can see by prop2, my validation function is starting to get pretty messy with so many 'if-then-iterate-again' blocks as I have to account for not only ranges but a list of permitted values. With the validation code and this rule array, my script is getting rather bulky.
The question is, how can I structure my class or class properties or the validation code or any other aspect of my script to be as short and concise as possible to allow property range and value enforcement? Is there a language feature or trick to handle this more elegantly? Have I reached a brick wall, the limit of this language? Are there any examples from other languages that can easily implement this which can provide some clue?
getters and setters
class Main {
private $prop1;
private $prop2;
private $prop3;
public function __construct( $p1 , $p2 , $p3 )
{
$this->setProp1($p1);
$this->setProp2($p2);
$this->setProp3($p3);
}
public function setProp1($p1)
{
// conditional checking for prop1
if(!$ok) throw new Exception('problem with prop1');
$this->prop1 = $p1;
}
//.. and so on
}
I ran into a similar issue the other day. Here's what I would do:
private $props;
private $rules;
function __construct($params) {
// or you can get the rules from another file,
// or a singleton as I suggested
$this->rules = array (array('type' => 'range', 'min' => 10, 'max' => 20),
array('type' => 'in_set', 'allowed' => array(1,2,3)));
for ($i=0; $i<count($params); $i++) {
if ($this->check($params[$i], $this->rules($i))
$this->props[$i] = $params[$i];
else
throw new Exception('Error adding prop ' . $i);
}
}
function check($value, $rule) {
switch($rule['type']) {
case 'range':
return ($rule['min'] <= $value && $value <= $rule['max']);
case 'in_set':
return (in_array($value, $rule['allowed']));
// and so on
}
}
If you have many parameters, you can use an array and iterate through that.
If your validation rules are always going to be the same, you can put them in a separate file and load that in your constructor or whatever.
EDIT: By the way, there is really no point in testing type in PHP. It is both not very reliable and unnecessary.
EDIT 2: Instead of having a global variable with the rules, you can use a Singleton:

PHP - get_class_methods() Problem

I've this sample code:
class A
{
public function A_A() { /* ... */ }
public function A_B() { /* ... */ }
}
class B extends A
{
public function B_A() { /* ... */ }
public function B_B() { /* ... */ }
public function B_C()
{
return get_class_methods($this);
}
}
$a = new A();
$b = new B();
Doing this:
echo '<pre>';
print_r($b->B_C());
echo '</pre>';
Yields the following output:
Array
(
[0] => B_A
[1] => B_B
[2] => B_C
[3] => A_A
[4] => A_B
)
How can I make it return only the following methods?
Array
(
[0] => B_A
[1] => B_B
[2] => B_C
)
I've a method in class A that should call all the methods in class B, the problem is of course that it leads to a infinite loop due to the values returned by get_class_methods().
You might need full strength Reflection. However, before you go there, it might be worth trying something like this.
array_diff(get_class_methods($this), get_class_methods(get_parent_class($this)))
You can't. Part of the functionality of extending a class is that you get all of the methods of the class you extended, in the new class, identical to as if you defined them in the new class itself.

Categories