I'm learning php unit test. I've question; how to set property value from method? Here is my example code:
class Variables
{
public $date;
public function setDate(\DateTime $date) {
$this->date = $date;
}
}
class Process
{
public function process(Variables $var) {
if ($var->date->getTimeStamp() > 0) {
return 'success';
}
return 'failed';
}
}
class ProcessTest extends PHPUnit_Framework_TestCase
{
public function testProcess()
{
$mock = \Mockery::mock('Variables');
$mock->date = new \DateTime();
$procy = new Process();
$actual = $procy->process($mock);
$this->assertEquals('success', $actual);
}
}
Like in the codes above, I know, I can set property date by:
$mock->date = new \DateTime();
because it's public.
What if the property date is private or protected? How to set from mockery? I tried to do something like this, but got an error.
$mock->shouldReceive('setDate')->once()->andSet('date', new \DateTime());
Sample class that describes my question :
class Calculation {
protected $a;
protected $b;
protected $c;
public function __construct() {
;
}
public function setA($a) {
$this->a = $a;
}
public function setB($b) {
$this->b = $b;
}
public function call() {
$this->c = (int) $this->a + (int) $this->b;
}
public function getC() {
return $this->c;
}
}
I need your advice.
You would probably add an accessor to Variables, use it in Process::process() instead of accessing the public property, and thus, you would have to set up an expectation that the accessor is called when you invoke Process::process():
$date = new \DateTime();
$variables = \Mockery::mock('Variables');
$variables->shouldReceive('getDate')->withNoArgs()->andReturn($date);
$process = new Process();
$this->assertSame('success', $process->process($variables));
For reference, see:
http://docs.mockery.io/en/latest/reference/expectations.html
Related
I would like to bind a function (a method of a class) to another class. Any idea of how i could achieve this?
Here is an example of what i want:
class A {
protected $prop = "prop A";
function method($arg1, ...) {
return $this->prop;
}
}
class B {
protected $prop = "prop B";
// need help here
}
So i want to "bind" the method "method" of class "A" to class "B" so it'll be possible to do $b = new B(); $b->method($arg1, ...); and obtain "prop B";
Thanks in advance!!
I tried:
class B {
protected $instance;
protected $prop = "prop B";
public function __construct($instance) {
$this->instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array([$this->instance, $method], $args);
}
}
$b = new B(new A());
$b->method();
But still outputing "prop A";
I tried this too:
class B {
protected $prop = "prop B";
public function __call($method, $args) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
$a = new A();
$b = new B();
$b->method = $a->method;
$b->method();
But i'm getting this error: Closure::bind() expects parameter 1 to be Closure, null given....
At last i tried this too:
class B {
protected $instance;
protected $prop = "prop B";
public function __construct($instance) {
$this->instance = $instance;
}
public function __call($method, $args) {
$new_method = $this->instance->$method->bindTo($this);
return call_user_func_array($new_method, $args);
}
}
$b = new B(new A());
$b->method();
Here, an error says $this->instance->$method is null
Using dependency injection, you can access the passed object:
class A {
public function speak() { return ‘meow’; }
}
class B {
public function __construct($obj) {
$this->a = $obj;
}
}
$demo = new B( new A));
print $demo->a->speak();
// => meow
From here, if you want B->speak to refer to A->speak:
class A {
public function speak() { return ‘meow’; }
}
class B {
public function __construct($obj) {
$this->a = $obj;
}
public function speak() {
return $this->a->speak();
}
}
$demo = new B( new A));
print $demo->a->speak(); // meow
print $demo->speak(); // meow
Or, if B is a special kind of A:
// use obj A above
class B extends A {
// do stuff B knows
}
$demo = new B;
print $demo->speak();
// => meow
If you’re wanting the exact same method in both classes, perhaps what you’re looking for is traits. Traits are more or less an include for objects which lets objects “share” code. (Personally I think it’s a fancy way of violating DRY and is better handled with DI... but smarter people than I have included it in the language)
Using traits would be something like this (double check docs, I’ve never used this)
trait sharedMethod {
public function speak() {
return $this->prop;
}
}
class A {
use sharedMethod;
public $prop = “I’m from A”;
}
class B {
use sharedMethod;
public $prop = “I’m from B”;
public function __construct(object $a) {
$this->a = $a;
}
/**
* use this to get A’s method, or omit to keep B’s method
*/
public function speak() {
return $this->a->speak();
}
}
$demo = new B( new A));
print $demo->speak(); // I’m from A
// if you don’t override the method
$demo = new B( new A));
print $demo->speak(); // I’m from B
so a class:
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
its beign created and updated:
$obj = new ToBeUsed();
$obj->setSomething('a');
and passed to another object
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //// !!!!! THIS IS BAD!
}
}
now a classic DI example, except that the passed object should be "dulled" - only some methods are allowed to use. E.g. getSomething() is allowed to use, but setSomething() is not. What pattern / practice can get away with it? There used to be friend classes is C but its Php...
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$dbg = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2);
if(count($dbg) > 1){
return;
}
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
echo $this->obj->getSomething().PHP_EOL; // a
$this->obj->setSomething('b'); // this does nothing
echo $this->obj->getSomething().PHP_EOL; // a
}
}
$obj = new ToBeUsed();
$obj->setSomething('a');
$obj2 = new UseIt($obj);
$obj2->work();
Alternatively, you can perform more complex checks on debug_backtrace() output.
I would probably do something with Interfaces, it doesn't prevent a method form being used. But "they" (whoever they is) would be using it outside of the Interface for $obj.
Like this:
class ToBeUsed implements ToBeUsedInterface
{
private $a;
public function getSomething()
{
return $this->a;
}
public function setSomething($a)
{
$this->a = $a;
}
}
interface ToBeUsedInterface{
public function getSomething();
}
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsedInterface $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //This now exists outside of the interface for $obj
}
}
In terms of IDE's this would prevent the methods from auto-completing as well.
The only other thing I can think of, ( besides the other answer ) would be to set the method to protected and then use ReflectionMethod to change the viability, when you want to use it.
Another Option, is Using Reflection
class ToBeUsed
{
private $a;
public function getSomething()
{
return $this->a;
}
protected function setSomething($a)
{
$this->a = $a;
}
}
$ToBeUsed = new ToBeUsed();
$ReflectionMethod = new ReflectionMethod($ToBeUsed, 'setSomething');
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invoke($ToBeUsed, 'foo');
echo $ToBeUsed->getSomething();
Outputs:
foo
You can see it live here
And Obviously sense it's protected under normal conditions, it could not be used inside UseIt. If I was going to use this for any amount of code, I would extend or wrap the Reflection class. Just to make the call a bit more concise, like this:
class MyReflector
{
public static function invoke($class, $method, ...$args)
{
$ReflectionMethod = new ReflectionMethod($class, $method);
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invokeArgs($class, $args);
}
}
$ToBeUsed = new ToBeUsed();
MyReflector::invoke($ToBeUsed,'setSomething', 'foo');
Please note I got all fancy with the variadic ...$arg which is for PHP 5.6+ it just lets you do
MyReflector::invoke($ToBeUsed,'setSomething', 'foo', 'bar');
And $args would be ['foo','bar'] in the first example it's just ['foo'] which can be used for invokeArgs for the second argument which takes an array of arguments to pass on to the actual method.
So here's the class with the method today(). Is it possible to call today() without requiring an instantiated class object to run it?
i.e. without using MyDateClass::today()
<?php
Class MyDateClass
{
public $mm;
public $dd;
public $yyyy;
function __construct($mm, $dd, $yyyy)
{
$this->mm = $mm;
$this->dd = $dd;
$this->yyyy = $yyyy;
}
function today()
{
return date('Y-m-d');
}
}
?>
MyDateClass::today() - this means you call a static method and static methods do not create an instance of a class unless there is a code which creates an instance. But your today() is not static(no static word).
Static function is more like a simple function than a class method.
Class MyDateClass
{
public $mm;
public $dd;
public $yyyy;
public $timestamp;
function __construct($mm, $dd, $yyyy)
{
$this->mm = $mm;
$this->dd = $dd;
$this->yyyy = $yyyy;
}
function printDate(){
echo $this->dd.'.'.$this->mm.'.'.$this->yyyy;
}
static function today()
{
return date('Y-m-d');
}
}
MyDateClass::today(); // no instance
$instance1 = new MyDateClass('01','05','2015'); //instance1
$instance2 = new MyDateClass('01','05','2014'); //instance2
$instance1->printDate(); // prints 05.01.2015
$instance2->printDate(); // prints 05.01.2014
If I have a setter and getter methods below :
<?php
class Name{
protected $first ;
public function setNameType($value) {
$this->first = $value;
}
public function getNameType() {
return $this->first;
}
}
$name = new Name;
$name->setNameType("My Name");
echo $name->getNameType();
?>
and a construct method like this
<?php
class Name{
protected $first ;
public function __construct($value) {
$this->first = $value;
}
public function getNameType() {
return $this->first;
}
}
$name = new Name("My Name");
echo $name->getNameType();
?>
Can I use the two interchangeably at all times or is there situations where one will be most prefered over the other ?
There is also some great explaination about your question: http://www.potstuck.com/2009/01/08/php-dependency-injection/
Try this website. It explains all with examples.
http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern
Generally you would use constructors to set values if your class cannot exist or doesn't make sense without the value. If the value is allowed to be changed, than add a setter. If it should never be changed after construction, then don't add a setter.
An example code:
class Book {
public function __construct() {
$registry = RegistrySingleton::getInstance();
$this->_database = $registry->database;
// or
global $databaseConnection;
$this->_database = $database;
}
}
class Book {
private $_databaseConnection;
public function __construct() { }
public function setDatabaseConnection($databaseConnection) {
$this->_databaseConnection = $databaseConnection;
}
}
$book = new Book();
$book->setDatabase($databaseConnection);
$book = new Book($databaseConnection, $configFile);
$book = new Book();
$book->setDatabase($databaseConnection);
$book->setConfigFile($configFile);
class Container {
public static $_database;
public static function makeBook() {
$book = new Book();
$book->setDatabase(self::$_database);
// more injection...
return $book;
}
}
And then:
$book = Container::makeBook();
I have the following class written for PHP 5.4.x. Should this work as I expect?
class SqlBuilder {
private $dbTable;
private $action;
private $data;
private $clause;
public function toString() {
// $sql = generate sql string
// [...]
return $sql;
}
[...]
public function setClause($clause) {
$this->clause = $clause;
}
public function setDbTable($dbTable) {
$this->dbTable = $dbTable;
}
public function setAction($action) {
$this->action = $action;
}
}
$sql = (new \dbal\SqlBuilder())
->setAction($this->action)
->setClause($this->clause)
->setDbTable($this->dbTable)
->toString();
I am expecting to be able to access all of my setter methods. Instead I see the following error:
Fatal error: Call to a member function toString() on a non-object )
This seems to work:
$builder= new \dbal\SqlBuilder();
$builder->setAction($this->action)
$builder->setClause($this->clause)
$builder->setDbTable($this->dbTable)
$sql = $builder->toString();
But I know that this works as well:
class Foo
{
public $a = "I'm a!";
public $b = "I'm b!";
public $c;
public function getB() {
return $this->b;
}
public function setC($c) {
$this->c = $c;
return $this;
}
public function getC() {
return $this->c;
}
}
print (new Foo)
->setC($_GET["c"])
->getC(); // I'm c!
I've used this style of syntax in Javascript before. Is there a way to make it work in PHP?
What you are asking about is called method chaining. In order for it to work the way you want, each method call needs to return a reference to the object that you are calling. So,
->setAction($this->action)
// needs to return $this; so that
->setClause($this->clause)
// knows what to operate upon and in turn needs to return $this; so that
->setDbTable($this->dbTable)
// can do the same
Try :
public function setClause($clause) {
$this->clause = $clause;
return $this;
}
public function setDbTable($dbTable) {
$this->dbTable = $dbTable;
return $this;
}
public function setAction($action) {
$this->action = $action;
return $this;
}