I want to know the right way to handle this scenario: modify a variable within a method with a service. I know you could just do:
$input = $this->modify($input)
But that doesn't feel like the correct OOP way of handling the situation. Please see the inline comments.
class myClass {
public function __construct(Service $service)
{
$this->service = $service;
}
public function work($input)
{
// $input = SOMETHING
$this->service->modify($input);
// $input = SOMETHING MODIFIED
Entity::create($input);
}
}
It can be achieved by passing in the input as reference:
public function modify(&$input) {
// ^ See what I did there?
A better approach would be to return the modified input, and assign it again:
$input = $this->service->modify($input);
Don't start messing with references until you know exactly what you're doing.
Related
I'm self-studying the PHP language. And I'm focused on the latest PHP OOP language.
I search for some "ready-to-install" PHP software and as I scan for some references to search and know, I saw lines of code with a structure like this (can't remember so I'll create my own):
$myapp->settings->getValue('openforum');
$myapp->settings->setValue('closeformaintenance', '1');
So my question is, how can I reproduce the code above? I don't know what term to use that line of code (objects, I guess?).
Something like this:
$newLogin->search($uid)->setLogin($dateToday);
Like that. I really need to do that way so I can organize my coding structure. Thanks by the way.
And also for the final question, IS THAT POSSIBLE?
Here's a fairly straight forward way of looking at it, using dependency injection.
Try it out: https://3v4l.org/iSJgL
Note, the below requires PHP 7 due to the string type hint. Remove that and I believe it should work in 5.6 just fine.
<?php
$myapp = new MyApp(new SettingsBag([
'works' => false,
'random' => rand(),
]));
var_dump($myapp->settings()->get('random'));
var_dump($myapp->settings()->get('works'));
// Let's change it up...
$myapp->settings()->set('works', true);
// Now it should be true.
var_dump($myapp->settings()->get('works'));
These would normally have namespaces like \App and/or \App\Configuration, but I ignore that here so it's easier to follow:
class MyApp {
private $settings_bag = null;
function __construct(SettingsBag $settings_bag)
{
$this->settings_bag = $settings_bag;
}
public function settings()
{
return $this->settings_bag;
}
}
class SettingsBag {
private $settings = null;
function __construct(array $settings = [])
{
$this->settings = $settings;
}
public function set(string $key, $value)
{
return $this->settings[$key] = $value;
}
public function get(string $key)
{
return $this->settings[$key];
}
}
What you try to achieve is called method chaining. You can get this by the following:
<?php
class TestClass {
private $val = '';
public function test1($val) {
$this->val = $val;
return $this;
}
public function test2() {
echo 'Hello '.$this->val;
}
}
$test->test1('World')->test2(); // Hello World
You have simply to return the instance of the object on the method to allow the method chaining.
You can read more here.
It's method chaining.
See code below:
class T {
public function test() {
// do something
return $this;
}
}
$x = new T;
$x->test()->test();
Before anyone says anything. I've been to many articles, and I just can't wrap my head around the purpose of a constructor.
I've found an example on a site. Here's the code:
<?php
class dogtag {
public $Words;
}
class dog {
public $Name;
public $DogTag;
public function bark() {
print "Woof!\n";
}
public function __construct($DogName) {
print "Creating $DogName\n";
$this->Name = $DogName;
$this->DogTag = new dogtag;
$this->DogTag->Words = "My name is $DogName. If you find me, please call 555-1234";
}
}
class poodle extends dog {
public function bark() {
print "Yip!\n";
}
}
$poppy = new poodle("Poppy");
print $poppy->DogTag->Words . "\n";
?>
It echoes out the following:
Creating Poppy My name is Poppy. If you find me, please call 555-1234
May someone please explain this code to me like I'm 5. I just don't get it.
A constructor is used to do any initial process required once a new class object was initiated. Ok so that was pretty fancy right? Lets break down what that means with an example. Lets first make a class, and inside that class put some variables, some functions, and a constructor! (It's easier for me to explain the concept behind a constructor with a simpler class. babysteps.)
<?php
class myInfo
{
protected $limit;
public function __construct($limit = 10)
{
$this->limit = $limit;
}
public function awesomesauce() {
//...some random code...
}
}
$variable = new myInfo();//initiating an instance of class myInfo
?>
The code $variable = new myInfo(); is initiating an object of type myInfo. When that initiation happened, the php code knows that right away, the constructor function public function __construct($limit = 10) has to be called. In this case, the value of $limit is made to be 10. However, if I later on do the following code:
$variableTwo = new myInfo(20);
The variable passed inside the parenthesis would be passed directly into the constructor function.
So depending on the specific situation I could either pass no variables when creating an instance of type myInfo, in which case the constructor function would use the default value of ($limit = 10) or I could pass a value. If php did not have the ability to use constructors, I would literally have to manually change that variable with a new line of code every time I initiated a new object of class myInfo. Now this is just a simple example. Imagine if you need to not only initiate values, but run functions that work with API's somewhere else on your server. You can definitely see the benefit of having this happen automatically instead of being forced to write multiple lines of code every single time an object is initiated.
Let me know if that helped.
here is the following code sample
<?php
interface iFS
{
public function read();
public function write($data);
}
class MyClass
{
protected $_fs = null;
public function __construct(iFS $fs)
{
$this->_fs = $fs;
}
public function run(array $list)
{
foreach ($list as $elm)
{
$this->_fs->write($elm);
}
return $this->_fs->read();
}
}
class MyTests extends PHPUnit_Framework_TestCase
{
public function testFS()
{
$mock = $this->getMock('iFS');
$mock->expects($this->at(0))
->method('read')
->will($this->returnValue('tototatatiti'));
$c = new MyClass($mock);
$result = $c->run(array('toto', 'tata', 'titi'));
$this->assertEquals('tototatatiti', $result);
}
}
This is absolutely not a real case but it make happen something strange with phpunit and at($index) feature.
My question is pretty simple, is it normal that the test fails?
I explicitely asked to return "tototatatiti", but it never happens...
When
I remove the line $this->_fs->write($elm);
or
I replace $mock->expects($this->at(0)) by $mock->expects($this->once())
The test pass to green
Is there something I don't understand?
EDIT:
$mock->expects($this->at(3))
->method('read')
->will($this->returnValue('tototatatiti'));
=> Will make the test pass green...
According to PHPUnit source code we have:
public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->currentIndex++;
return $this->currentIndex == $this->sequenceIndex;
}
each time the PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex attempts to match an invocation, the protected variable $currentIndex is incremented, therefore your call to write first causes it to become 0, and then it does not match read.
The second call, to read causes the value to become 1, so it does not match either.
Looks like it indeed applies to the whole object, which is useful if you need to make sure that a sequence of calls occurs in a particular order.
For instance, assuming the write method was only called once, you could have something like:
$mock->expects($this->at(0))
->method('write');
$mock->expects($this->at(1))
->method('read')
->will($this->returnValue('tototatatiti'));
This ensures that the write method is indeed called before the read method.
I think the phpunit at() features is not usefull to stub different return result for a mocked method if the mocked object contains some other methods witch are calls too...
If you want to test something like:
$stub->expects($this->at(0))
->method('read')
->will($this->returnValue("toto"));
$stub->expects($this->at(1))
->method('read')
->will($this->returnValue("tata"));
You should better use something like
$stub->expects($this->exactly(2))
->method('read')
->will($this->onConsecutiveCalls("toto", "tata));
$this->admin_model->list_user()
I am writing most of the time my programs in OOP PHP. but I am writing like this...
$this->hello_world().
The above code is CodeIgniter and I think CakePHP also following same coding style.
Please give me simple example how to make my "hello_world" like
$this->something->hello_world().
Thanks you on advance.
Surya
Its nothing special; $this->admin_model is a property which contains an object, and for all purposes is identical to $object->method();
A step by step would look like:
$this->property = new MyObjectWIthADoItMethod();
$this->property->DoIt();
something is just an object of a type which has hello_world() method.
So:
class Something
{
public function hello_world()
{
echo 'Hello, big world!';
// Do work.
}
}
class Program
{
private $something;
public function Run()
{
$this->something = new Something();
$this->something->hello_world()
}
}
$program = new Program();
$program->Run();
I need to call a static function from an object using the Singleton design, but using a variable as the class name.
The best way, $class::getInstance();, is only available in PHP 5.3, and the other way I found, call_user_func(array($class, 'getInstance'));, results in the maximum execution time being breached. Does anyone know why this is happening, or of a way for this to work / a workaround?
I know that this is not the best way for things to be done, and the Singleton design pattern would not be my first choice, but unfortunately it's not up to me.
Thanks in advance to anyone who contributes :)
I include the rest of the code involved:
abstract class Library
{
protected function __construct(){}
final private function __clone(){}
final public static function &getInstance()
{
static $libs = array();
$lib = get_called_class();
if(!isset($libs[$lib])) $libs[$lib] = new $lib();
return $libs[$lib];
}
}
public function &loadLibrary($lib)
{
// Filter $lib, and load the library class file...
// Following only works in PHP 5.3
// return $lib::getInstance();
// Following results in maximum execution time being breached.
return call_user_func(array($lib, 'getInstance'));
}
}
$someLibrary =& loadLibrary('someLibrary');
someLibrary.php:
class someLibrary extends Library
{
protected function __construct(){}
// Code...
}
Soulmerge make a valid point saying that get_called_class() is only in PHP 5.3, and therefore I must be using it, but alas, I just cheat my way round things as I usually do (Thanks to Chris Webb from http://www.septuro.com/ for the code - far too complex to be any of my own!).
if(!function_exists('get_called_class'))
{
class classTools
{
static $i = 0;
static $fl = null;
static function get_called_class()
{
$bt = debug_backtrace();
if(self::$fl == $bt[2]['file'].$bt[2]['line']) self::$i++;
else {
self::$i = 0;
self::$fl = $bt[2]['file'].$bt[2]['line'];}
$lines = file($bt[2]['file']);
preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/', $lines[$bt[2]['line']-1], $matches);
return $matches[1][self::$i];
}
}
function get_called_class()
{
return classTools::get_called_class();
}
}
I shall go over all my code again, as there must be a loop somewhere. Back to the drawing board I go :(
You should start by determining what it is that takes you into an infinite loop. Does your constructor (someLibrary::__construct()) have any code that directly/indirectly calls Library::getInstance(), for example?
EDIT get_called_class() was introduced in PHP 5.3, so if your code actually works, you're already running 5.3
you could try to solve this with eval().
To get you an idea:
$theVar = "relvantClassName";
$someObject = eval($theVar::getInstance());
$result = $someObject->performAction();