I am building a scheduler that will take a callback function and will execute that function a given amount of times, and in between a given amount of delay. Below is that the interface for what the functionality looks like.
Side note I am using the Laravel Framework;
public function testBasicTest()
{
$count = 0;
$schedule = new NodeScheduler();
$schedule->retries(2)->delay(100000)->do(function() use ($count) {
$count++;
});
$this->assertEquals($count === 1);
}
This is my test for this piece of functionality and as you can see i want count to equal 2 by the end of it.
My class looks like this;
class NodeScheduler
{
protected $retries = 1;
protected $milliseconds = 10000;
public function __construct()
{
return $this;
}
public function retries($numberOfRetries)
{
$this->retries = $numberOfRetries;
return $this;
}
public function delay($milliSeconds)
{
$this->milliSeconds = $milliSeconds;
return $this;
}
public function do($callback)
{
for($i = 0; $i < $this->retries; $i++){
$callback(); // <<<<<< How Do I Inject The $count Variable Here?
usleep($this->milliseconds);
}
return;
}
}
My test fails with:
Failed asserting that 2 matches expected 0.
Strangely I don't get $count is undefined.
I think i am close, any help greatly appreciated
When you use() a variable from the outer scope inside a function, this creates a copy of the variable into the function's inner scope (an exception is if you're use()ing an object).
If you want to import a variable from the outer scope and modify it, you'll need to pass it in by reference:
$schedule->retries(2)->delay(100000)->do(function() use (&$count) {
$count++;
});
Edit: Also, what #Arno and #Oniyo pointed out: either use assertEquals(1, $count) or use assertTrue($count === 1)
I think you are doing two things wrong
Firstly: As #Arno pointed out,
$this->assertEquals($expected, $actual);
Secondly: From what I see in your code, the loop will run $this->retries's iterations. So, $this->assertEquals($expected, $actual) should be
$this->assertEquals(2, count);
Good luck man!
Related
I am learning PHP using reviewing some complete PHP projects. (I know that this is a bad way, but my goal is not to be a PHP programmer!) Anyway, I faced with the following function that is weird a little to me:
function filterIt($filter): callable {
return function ($value) use ($filter) {
return filter_var($value, $filter) !== false;
};
}
I don't know what this function do and why it has been witter in such a way that a function is inside of another function! inner function returns something and main function also. Why we need such complicated function? or maybe one can make it simpler?
For this reason I want to write isEven() function as callable function like above. But I have no idea!
I don't know what that function do, but by mimicking from that:
function isEven($num): callable {
return function () use ($num) {
return $num % 2 == 0;
};
}
I couldn't debug this using var_dump or print_r .
Not sure how you are calling this in you're test, but as the function is actually returning a callable you would be able to debug it once you run it like this:
<?php
function isEven($num): callable {
return function () use ($num) {
return $num % 2 == 0;
};
}
var_dump(isEven(14)());
IMO the summary of the filterIt() function is "give me an anonymous function that filters based on $filter", and then that callable is likely passed somewhere else to be applied. I would venture to guess that the author wrote this function as a shorthand so that they did not need to write out the anonymous function definition over and over for different values of $filter.
Below is a simplified example of such behaviour:
class ExampleCollection {
protected $filters = [];
public function __construct(protected array $items) {}
public function addFilter(callable $filter) {
$this->filters[] = $filter;
}
public function getFiltered() :\Generator {
foreach($this->items as $item) {
foreach($this->filters as $filter) {
if( $filter($item) ) {
continue 2;
}
}
yield $item;
}
}
}
function makeMultipleFilter(int $value) :callable {
return function($a)use($value) {
return $a % $value === 0;
};
}
$c = new ExampleCollection([1,2,3,4,5,6,7,8,9,10]);
// add filters to exclude multiples of 3 and 4
$c->addFilter(makeMultipleFilter(3));
$c->addFilter(makeMultipleFilter(4));
foreach($c->getFiltered() as $item) {
printf("Got: %d\n", $item);
}
Output:
Got: 1
Got: 2
Got: 5
Got: 7
Got: 10
But I agree with Chris Haas' comment that the author's intent is not always obvious and is best asked of them, if possible. Further to that, not all code is exemplary, even if someone exemplary happens to have written it. Everyone writes themselves into a corner sometimes and has to resort to a confusing and/or ugly piece of code to get around it. Which is not to say that this is what that is, though it is somewhat confusing on first read.
In PHP using method chaining how would one go about supplying a functional call after the last method being called in the chain?
Also while using the same instance (see below). This would kill the idea of implementing a destructor.
The end result is a return value and functional call of private "insert()" from the defined chain properties (of course) without having to call it publicly, no matter of the order.
Note, if I echo (__toString) the methods together it would retrieve the final generated unique code which is normal behavior of casting a string.
Example below:
class object
{
private $data;
function __construct($name) {
// ... some other code stuff
}
private function fc($num) {
// some wicked code here
}
public function green($num) {
$this->data .= fc($num*10);
return $this;
}
public function red($num) {
$this->data .= fc($num*25);
return $this;
}
public function blue($num) {
$this->data .= fc($num*1);
return $this;
}
// how to get this baby to fire ?
private function insert() {
// inserting
file_put_content('test_code.txt', $this->data);
}
}
$tss = new object('index_elements');
$tss->blue(100)->green(200)->red(100); // chain 1
$tss->green(0)->red(100)->blue(0); // chain 2
$tss->blue(10)->red(80)->blue(10)->green(0); // chain 3
Chain 1, 2, and 3 would generated an unique code given all the values from the methods and supply an action, e.g. automatically inserting in DB or creating a file (used in this example).
As you can see no string setting or casting or echoing is taking place.
You could keep a list of things that needs to be initialised and whether they
have been so in this instance or not. Then check the list each time you use
one of the initialisation methods. Something like:
class O {
private $init = array
( 'red' => false
, 'green' => false
, 'blue' => false
);
private function isInit() {
$fin = true;
foreach($this->init as $in) {
$fin = $fin && $in;
}
return $fin;
}
public function green($n) {
$this->init['green'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function red($n) {
$this->init['red'] = true;
if($this->isInit()) {
$this->insert();
}
}
public function blue($n) {
$this->init['blue'] = true;
if($this->isInit()) {
$this->insert();
}
}
private function insert() {
echo "whee\n";
}
}
But personally I think this would be more hassle then it's worth. Better imo
to expose your insert method and let the user of you code tell when the
initialisation is finished. So something that should be used like:
$o->red(1)->green(2)->blue(0)->insert();
-update-
If it's the case that it's impossible to predict what functions need to be called
you really do need to be explicit about it. I can't see a way around that. The reason
is that php really can't tell the difference between
$o1 = new A();
$o2 = $o1->stuff();
and
$o2 = (new A())->stuff();
In a language that allows overloading = I guess it would be possible but really
really confusing and generally not a good idea.
It is possible to move the explicit part so that it's not at the end of the call
chain, but I'm not sure if that would make you happier? It would also go against
your desire to not use another instance. It could look something like this:
class O {
public function __construct(InitO $ini) {
// Do stuff
echo "Whee\n";
}
}
class InitO {
public function red($n) {
return $this;
}
public function green($n) {
return $this;
}
public function blue($n) {
return $this;
}
}
$o = new O((new InitO())->red(10)->red(9)->green(7));
You can of course use just one instance by using some other way of wrapping
but the only ways I can think of right now would look a lot uglier.
Im with PeeHaa, this makes no sense! :)
Only chance to have something magically happen after the last chain was used (without being able to look into the future) is a Destructor/Shutdown function OR a manually cast/call to insert()
You can also decide to implement this statically without using objects.
<?php
class Object
{
private static $data;
public static function set($name)
{
// ... some other code stuff
}
private static function fc($num)
{
// some wicked code here
}
public static function green($num)
{
self::$data .= self::fc($num*10);
return new static;
}
public static function red($num)
{
self::$data .= self::fc($num*25);
return new static;
}
public static function blue($num) {
self::$data .= self::fc($num*1);
return new static;
}
// how to get this baby to fire ?
public static function insert()
{
// inserting
file_put_content('test_code.txt', self::$data);
}
}
//$tss = new object('index_elements');
$Object::set('index_elements')->blue(100)->green(200)->red(100)->insert(); // chain 1
$Object::set('index_elements')->green(0)->red(100)->blue(0)->insert(); // chain 2
$Object::set('index_elements')->blue(10)->red(80)->blue(10)->green(0)->insert(); // chain 3
?>
Ok let's see a code example
<?php
// map dummy class
class map
{
// __call magic method
public function __call($name, $args)
{
return $this;
}
}
// now we chain
$map = new map;
// let's find me
$map->start('here')
->go('right')
->then()
->turn('left')
->and('get water')
->dontEat()
->keep('going')
->youShouldSeeMe('smiling');
here we don't know what the last method would be and we need to trigger a kinda operation or event once we hit the end.
According to data structure we can call this the LIFO stack. (Last in first out)
so how did i solve this on PHP?
// i did some back tracing
... back to the __call function
function __call($name, $args)
{
$trace = debug_backtrace()[0];
$line = $trace['line'];
$file = $trace['file'];
$trace = null;
$getFile = file($file);
$file = null;
$getLine = trim($getFile[$line-1]);
$line = null;
$getFile = null;
$split = preg_split("/(->)($name)/", $getLine);
$getLine = null;
if (!preg_match('/[)](->)(\S)/', $split[1]) && preg_match('/[;]$/', $split[1]))
{
// last method called.
var_dump($name); // outputs: youShouldSeeMe
}
$split = null;
return $this;
}
And whoolla we can call anything once we hit the bottom.
*(Notice i use null once i am done with a variable, i come from C family where we manage memory ourselves)
Hope it helps you one way or the other.
I'm still new to PHP and I am having a lot of trouble. I'm used to languages like C,C++, and Java, and this one is kinda confusing me. Basically my problem is that I have the following code:
class File_Reader
{
protected $text;
public function Scan_File (){}
public function Skip_Whitespace(&$current_pos)
{
//skip past whitespace at the start
while (($current_pos < strlen($text) && ($text[$current_pos] == ' ')))
$current_pos++;
}
public function __construct(&$file_text)
{
$text = $file_text;
}
}
class Times_File_Reader extends File_Reader
{
Public Function Scan_File()
{
$errors = array();
$times = array();
$current_time;
$cursor = 0;
$line = 0;
while ($cursor < strlen($text))
{
Skip_Whitespace($cursor);
//....lots more code here...
return $times;
}
}
}
but when I try to run it, it tells me that $time and Skip_Whitespace are both undefined. I don't understand, they should have been inherited. I tried putting an echo command in the File_Reader constructor and it does enter the constructor when I create my Times_File_Reader.
Oh, and for completeness, here is where I declare my Times_File_Reader:
include 'File_Readers.php';
$text = file_get_contents("01_CT.txt");
$reader = new Times_File_Reader($text);
$array = $reader->Scan_File();
I've been searching for an answer for hours to no avail, and deadline is approaching quickly. Any help would be appreciated. Thank you!
I believe that you need to note that you are using the class function by using
$this->Skip_Whitespace($cursor);
You need to set the property that you are passing into your constructor as a property of the class (the variables within methods are scoped in the same way as Java).
You do this using $this->property
// File_Reader
public function __construct(&$file_text)
{
$this->text = $file_text;
}
// Times_File_Reader
public function Scan_File()
{
$errors = array();
$times = array();
$current_time;
$cursor = 0;
$line = 0;
while ($cursor < strlen($this->text))
{
$this->Skip_Whitespace($cursor);
//....lots more code here...
return $times;
}
}
Edit - as an aside you seem to be using some wacky underscorecase/Titlecase hybrid. Best practice in PHP is to use lowerCamelCase for methods and CamelCase for class names.
class FileReader
class TimesFileReader
public function scanFile()
Also - you are passing your variables by reference (&$var) - you probably don't have to do this (the only valid use case I can think of for this is in certain situations using closures/anonymous functions). I'll admit the docs on this are not very clear. http://schlueters.de/blog/archives/125-Do-not-use-PHP-references.html
public function __construct($file_text)
{
$this->text = $file_text;
}
Working recently with the extension pthreads, i discovered an anomaly. I have a simple object with an internal state:
class Sum {
private $value = 0;
public function add($inc) { $this->value += $inc; }
public function getValue() { return $this->value; }
}
Now i created a Thread class that does something with this object:
class MyThread extends Thread {
private $sum;
public function __construct(Sum $sum) {
$this->sum = $sum;
}
public function run(){
for ($i=0; $i < 10; $i++) {
$this->sum->add(5);
echo $this->sum->getValue() . " ";
}
}
}
In my main function i created a Sum object, injected it into the thread and started it:
$sum = new Sum();
$thread = new MyThread($sum);
$thread->start();
$thread->join();
echo $sum->getValue();
I expected the result to be 50, because the thread had to increment the value 10 times by 5. But i got a 0!
More curious is that it's not the synchronization back into the main thread that failed but the thread even seems to forget its internal state on the way: The output of the echo inside the run() method is not the expected 5 10 15 20 25 30 35 40 45 50 but 0 0 0 0 0 0 0 0 0 0. Nobody is interfering with the thread - why does it not preserve its state?
Side note: If i do not start the thread but instead call the run()-method directly in the main thread ($thread->run();), the result is still the same. But if i now remove the extends Thread in the class declaration, it works perfectly and returns the expected 5 10 15 20 25 30 35 40 45 50.
Any object not descended from a pthreads definition will be serialized upon setting it a member of an object descended from pthreads.
Operations like += and [] use pointers internally, serialization is incompatible with pointers for other objects. In the manual on the introduction page, it states that any object intended to be manipulated by multiple contexts should extend Stackable, Thread or Worker, like
<?php
class Sum extends Stackable {
private $value = 0;
public function add($inc) { $this->value += $inc; }
public function getValue() { return $this->value; }
public function run(){}
}
class MyThread extends Thread {
public $sum;
public function __construct(Sum $sum) {
$this->sum = $sum;
}
public function run(){
for ($i=0; $i < 10; $i++) {
$this->sum->add(5);
echo $this->sum->getValue() . " ";
}
}
}
$sum = new Sum();
$thread = new MyThread($sum);
$thread->start();
$thread->join();
echo $sum->getValue();
?>
If Sum weren't using pointers you would have the option of retrieving the reference from the threaded object after join.
These are simple operations, you are not required to synchronize. The only time you should synchronize is when you plan to wait on an object or notify one.
The objects bundled with pthreads are very much more suited to this environment and are never serialized.
Please do read the intro in the manual and all the examples in the methods you wish to utilize to find out exactly what is what, then feel free to ask why :)
I know that users of PHP aren't used to having to do research, but we are pushing the envelope here, you will find there are correct ways to do things an incorrect ways, most of them are documented in examples, and anything thats not I'm sure will be extracted from me on SO and eventually find it's way to the documentation.
I'm not sure if the example you gave was testing out objects in particular, but the code you provided need not be two objects, and shouldn't be two objects either, consider the following:
<?php
class MyThread extends Thread {
public $sum;
public function run(){
for ($i=0; $i < 10; $i++) {
$this->add(5);
printf("%d ", $this->sum);
}
}
public function add($num) { $this->sum += $num; }
public function getValue() { return $this->sum; }
}
$thread = new MyThread();
$thread->start();
$thread->join();
var_dump($thread->getValue());
?>
It may be useful for you to see a couple more features in action with an explanation, so here goes, here's a similar example to yours:
<?php
class MyThread extends Thread {
public $sum;
public function __construct() {
$this->sum = 0;
}
public function run(){
for ($i=0; $i < 10; $i++) {
$this->add(5);
$this->writeOut("[%d]: %d\n", $i, $this->sum);
}
$this->synchronized(function($thread){
$thread->writeOut("Sending notification to Process from %s #%lu ...\n", __CLASS__, $thread->getThreadId());
$thread->notify();
}, $this);
}
public function add($num) { $this->sum += $num; }
public function getValue() { return $this->sum; }
/* when two threads attempt to write standard output the output will be jumbled */
/* this is a good use of protecting a method so that
only one context can write stdout and you can make sense of the output */
protected function writeOut($format, $args = null) {
$args = func_get_args();
if ($args) {
vprintf(array_shift($args), $args);
}
}
}
$thread = new MyThread();
$thread->start();
/* so this is synchronization, rather than joining, which requires an actual join of the underlying thread */
/* you can wait for notification that the thread is done what you started it to do */
/* in these simple tests the time difference may not be apparent, but in real complex objects from */
/* contexts populated with more than 1 object having executed many instructions the difference may become very real */
$thread->synchronized(function($thread){
if ($thread->getValue()!=50) {
$thread->writeOut("Waiting for thread ...\n");
/* you should only ever wait _for_ something */
$thread->wait();
$thread->writeOut("Process recieved notification from Thread ...\n");
}
}, $thread);
var_dump($thread->getValue());
?>
This combines some of the more advanced features in some simple examples, and is commented to help you along. On the subject of sharing objects, there's nothing wrong with passing around a Thread object if it contains some functionality and data required in other threads or stackables. You should aim to use as few threads and objects as possible in order to get the job done.
Your problem is that you are accessing the variable from the main thread and from the MyThread thread. The CPU caches the variable and it gets updated in the cache for MyThread but not in the cache for the main thread, so your both threads never see the others thread changes. In Java / C etc. there is the keyword volatile but I don't know if that exists in PHP.
I think you should try to call the methods in sum synchronized ( http://php.net/manual/en/thread.synchronized.php )
For example, instead of:
$this->sum->add(5);
Call:
$this->synchronized(function($thread){
$thread->sum->add(5);
}, $this);
I thought I am doing something wrong too. As mentioned [] and other operations using pointers will not work. This is the workaround:
class MyThread extends Thread {
public $table;
public function __construct($data) {
$this->table= $data;
}
public function run(){
//Set temporary array with current data
$temp = $this->table;
for ($i=0; $i < 10; $i++) {
//Add new elements to the array
$temp[] = $i . ' New Value';
}
//Overwrite class variable with temporary array
$this->table = $temp;
}
}
This works as we are using [] operation on a temporary function variable and than we set it as class variable.
Better example why is it necessary:
class MyThread extends Thread {
public $table;
public function __construct($data) {
$this->table= $data;
}
public function run(){
$this->addElem();
$temp = $this->table;
$temp[] = 1;
$this->table = $temp;
}
protected function addElem() {
$temp = $this->table;
$temp[] = $i . ' New Value';
$this->table = $temp;
}
}
So we can use and add new elements to the variable in more than one function.
The same will work for += and other operators, but you need the temporary variable for it.
Easy to extend function for this:
protected function overload($name, $val, $type = '[]'){
$temp = $this->$name;
switch($type){
case '[]':
$temp[] = $val;
break;
case '+=':
$temp += $val;
break;
case '.=':
$temp .= $val;
break;
}
$this->$name = $temp;
}
Eval could work here but I find this much safer.
I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)