Selenium takes > minute between commands - php

Selenium seems to be pausing for about a minute between each step (I haven't seen less than 60 seconds). Even steps that should be simple (like setSpeed) run at the same rate.
However, when I use the PHPUnit_Extensions_SeleniumTestCase class, I am able to run tests at normal speed. (Also, the slow steps run fine on a coworker's computer.)
Anyone know what I'm doing wrong? Thanks!
Here is the slow test:
debug_time(); // 0
require_once 'Testing/Selenium.php';
debug_time(); // 1
$s = new Testing_Selenium('*firefox', "http://google.com/");
debug_time(); // 2
$s->setSpeed(0);
debug_time(); // 3
$s->start();
debug_time(); // 4
var_export($s->getSpeed());
echo "\n";
debug_time(); // 5
$s->open('/');
debug_time(); // 6
$s->stop();
debug_time(); // 7
echo "done";
Here is the output for the slow test:
0 => 18:01:54.44488 (+ 0.00000)
1 => 18:01:54.45478 (+ 0.00990)
2 => 18:01:54.45645 (+ 0.00167)
3 => 18:02:54.97334 (+ 60.51688)
4 => 18:04:03.59346 (+ 68.62013)
NULL
5 => 18:05:04.11214 (+ 60.51867)
6 => 18:06:05.83747 (+ 61.72534)
7 => 18:07:06.63492 (+ 60.79744)
done
Here is the fast test, taken from the PHPUnit manual:
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
protected function setUp()
{
$this->setBrowser('*firefox');
$this->setBrowserUrl('http://google.com/');
}
public function testTitle()
{
$this->open('/');
$this->assertTitleEquals('Example Web Page');
}
}

The same here. Downgrade to Testing_Selenium-0.4.3 helped. Trying to find the reason. May be PHP5.3?

Related

Use schedules in Laravel settings

I have profiles that run on a schedule, in the settings of each profile there is a period of everyFiveMinutes type, Then in the kernel I use this
$tasks = ProfileExchange::where('active', true)->whereNotNull('frequency')->get();
foreach ($tasks as $task) {
$frequency = $task->frequency;
$schedule->command(RunExchange::class, ['--id' => $task->id])
->runInBackground()
->$frequency();
}
but if in setup I want to use this at('13:00') then I get an error, help me fix it
Your code won't work because a value of at('13:00') in $task->frequency will become this in your code:
$schedule->command(RunExchange::class, ['--id' => $task->id])
->runInBackground()
->at('13:00')();
It's a bad idea to run code from your database like this anyway, it opens you up to potential code injection.
If I were you, I'd change $task->frequency to be either "every 5 minutes", "every 10 minutes" and other similar options, then if-else or switch-case for them in your code:
if($task->frequency == "every 5 minutes") {
$schedule->command(RunExchange::class, ['--id' => $task->id])
->runInBackground()
->everyFiveMinutes();
} else if
...
Then you can do a regex check for whether $task->frequency is a time, and use at to run it at that time:
...
else if(preg_match("\d?\d:\d\d", $task->frequency)) {
$schedule->command(RunExchange::class, ['--id' => $task->id])
->runInBackground()
->at($task->frequency);
}
You'll need to change how you store the time in your database too, it will have to be 13:00 instead of at('13:00')

PHP - Multi threading and pools

I am using Pool object in PHP pthread, and made the following test script, to see how the pooling should work. I tought, that what pooling should do, is to get a given number of tasks, open up a maximum x number of workers, and assign them the tasks, and as soon as a worker finishes with a task, if more tasks are available, assign to that worker a new task.
Given the below example, and the above assumption:
class Work extends Threaded {
public $id;
public function __construct($id) {
$this->id = $id;
}
public function run() {
if ($this->id == 0) {
sleep(3);
echo $this->id . " is ready\n";
return;
} else {
echo $this->id . " is ready\n";
return;
}
}
}
$pool = new Pool(2, 'Worker', []);
for ($i=0; $i<4; $i++) $pool->submit(new Work($i));
while ($pool->collect());
$pool->shutdown();
I was expecting this script to output the following information:
1 is ready
2 is ready
3 is ready
0 is ready
because, there are essentially 2 workers available, and because of the sleep operatin the first worker stumbles upon, task 1,2,3 must be completed by the second worker.
Instead of this, the output I am getting is:
1 is ready
3 is ready
0 is ready
2 is ready
It is clear, that worker 1, gets assigned job 0, and job 2 at the get go, thus worker 2, after finishing job 1 and 3, just waits, instead of taking over job 2 from worker 1.
Is this a bug? Or is this intended to work this way?
My PHP version:
PHP 7.2.14 (cli) (built: Jan 9 2019 22:23:26) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
For some reason my Docker has crapped itself now that I've updated Windows to 1809, so posting untested. (So sorry, no output to give atm)
Modified existing code I use in a project with your counter + sleep.
$pool = new Pool(2);
foreach ([0,1,2,3] as $count) {
$pool->submit(
new class ($count) extends Threaded
{
private $count;
public function __construct(int $count)
{
$this->count= $count;
}
public function run()
{
if ($this->count== 0) {
sleep(3);
echo $this->count . " is ready\n";
} else {
echo $this->count . " is ready\n";
}
}
}
);
}
while ($pool->collect());
$pool->shutdown();
I use anonymous class (new class ($count) extends Threaded) as the submit() param.
On the server this runs perfectly, using a Docker instance running PHP ZTS 7.2.13 on Alpine 3.8
Let me answer: from what I know about pthreads in php, pool is like number of proccessing php.exe that can be run at the same times.
So in your case, you define two pool by using new Pool(2, 'Worker', []);
So let's make abstract explanation about it. There is 2 Pool, call it as PoolA and PoolB.
Loop from 0 to 3, each loop submit task to Pool.
There are 4 tasks from 0 to 3, lets call them by task0, task1, task2, task3.
When loop occur, from my perspective, it should be queue like this
PoolA -> submit task0
PoolB -> submit task1
PoolA -> submit task2
PoolB -> submit task3
But from class Work that will be task0, ... till task3.
Situation/Condition
You define some logic in run() => when parameter(in this case $id from constructor) is 0, then sleep(3).
From this situation, PoolA is which submit task0 that contains parameter($id) is value 0, PoolA will wait for 3 seconds. PoolA also submit task2.
On the other hand, PoolB submit task1 and task3, from this situation, doesn't need to wait for 3 seconds.
So when while($pool->collect()); is run, possible queue that's most likely happen
task1 (PoolB)
task3 (PoolB)
task0 (PoolA) ->>>> PoolA delayed because from task0 needs to sleep for 3 seconds
task2 (PoolA)
So I think it's correct when outputs are
1 is ready
3 is ready
0 is ready
2 is ready
There is a questions.
Why is only PoolA that delayed, even if PoolA delayed why task2 didn't submit to PoolB or why task1 or task3 not submit to PoolA??
Well, I don't understand too. I have task similar to yours, after many experiments, I'm not sure pthreads which use Pool & Threaded is multi-threading or multiprocessing.
Echoing from the individual threads can be deceiving.
I often find that they seem like they are executing before they are even called. I'd recommend avoiding echoing from inside threads, unless you don't care about the order, as it can be still be useful to test for specific circumstances, etc.
Below is some code which should resolve any questions of when the code is executing, as this code sorts the results by the actual time they executed. (It's also a nice example of how to get results back from a thread pool.)
<?php
class Work extends Threaded {
public $id;
public $data;
private $complete = false;
public function __construct($id) {
$this->id = $id;
}
public function run() {
$temp = array();
if ($this->id == 0) {
echo "<pre>".$this->id . " started (from inside threaded)";
$temp[] = array(microtime(true), $this->id . " started");
sleep(3);
}
echo "<pre>".$this->id . " is ready (from inside threaded)";
$temp[] = array(microtime(true), $this->id . " is ready");
$this->data = (array) $temp; // note: it's important to cast as array, otherwise you will get a volitile
$this->complete = true;
}
public function isDone() {
return $this->complete;
}
}
// we create a custom pool, to pass on our results
class ExamplePool extends Pool {
public $dataAr = array(); // used to return data after we're done
private $numTasks = 0; // counter used to know when we're done
private $numCompleted = 0; // keep track of how many threads finished
/**
* override the submit function from the parent
* to keep track of our jobs
*/
public function submit(Threaded $task) {
$this->numTasks++;
parent::submit($task);
}
/**
* used to wait until all workers are done
*/
public function process() {
// Run this loop as long as we have
// jobs in the pool
while ($this->numCompleted < $this->numTasks) {
$this->collect(function (Work $task) {
// If a task was marked as done, collect its results
if ($task->isDone()) {
//this is how you get your completed data back out [accessed by $pool->process()]
$this->dataAr = array_merge($this->dataAr, $task->data);
$this->numCompleted++;
}
return $task->isDone();
});
}
// All jobs are done
// we can shutdown the pool
$this->shutdown();
return $this->dataAr;
}
}
$pool = new ExamplePool(4);
for($i=0; $i<4; $i++) {
$pool->submit(new Work($i));
}
$retArr = $pool->process();
usort($retArr, 'sortResultsByTime'); // sort the results by time
// echo out the sorted results
echo "<br><br>";
for($i=0;$i<count($retArr);$i++){
echo number_format($retArr[$i][0], 4, ".", "").' '.$retArr[$i][1]."\n";
}
function sortResultsByTime($a, $b) {
return $a[0] > $b[0];
}
?>
Please note the code above yields this for me:
0 started (from inside threaded)
0 is ready (from inside threaded)
1 is ready (from inside threaded)
2 is ready (from inside threaded)
3 is ready (from inside threaded)
1609458117.8764 0 started
1609458117.8776 1 is ready
1609458117.8789 2 is ready
1609458117.8802 3 is ready
1609458120.8765 0 is ready
And as expected, the stuff echoed from inside the threads seems weird, however if you store the results, and sort them by the time they were executed, you can see it acts as expected.

mock atLeastOnce with concrete value, the rest not important

The question is in PHP, but applies to any language using the xUnit framework.
I want a mock, that expects 140 calls to method jump.
I need to verify, that at least once there is a call with 500 as parameter.
I don't care if all the calls are 500, but I need at least one that is called with 500.
$mock = $this->getMock('Trampoline', ['jump']);
$mock->expects($this->atLeastOnce())
->method('jump')
->with($this->equalTo(500))
->will($this->returnValue(true));
$sportsman->setTramploine($mock);
$sportsman->jumpToRandomHeights($times = 140); // this calls Trampoline->jump
// I need to verify the sportsman had jumped
// to the height of 500 at least once out of the 140 jumps he is performing
In the current code, the test fails after the first invocation of jump because the first invocation had a value different of 500, meaning the atLestOnce here only indicates that the method should be called, but not that it should be called with specific value among other calls.
Solution
The missing piece of information was using callbacks inside the with. Thanks to edorian's answer below this is what worked out:
$testPassed = false;
$checkMinHeight = function ($arg) use(&$testPassed)
{
if($arg === 500)
$testPassed = true;
// return true for the mock object to consider the input valid
return true;
}
$mock = $this->getMock('Trampoline', ['jump'])
->expects($this->atLeastOnce())
->method('jump')
->with($checkMinHeight)
->will($this->returnValue(true));
$sportsman->setTramploine($mock);
$sportsman->jumpToRandomHeights($times = 1000); // this calls Trampoline->jump
// I need to verify the sportsman had jumped
// to the height of 500 at least once out of the 1000 jumps he is performing
$this->assertTrue($testPassed, "Sportsman was expected to
jump 500m at least once");
You can but the best implementation withing PHPUnits mocking API, that I could come up with, still looks quite creepy.
Another way to solve this is a little more readable way would be to create your own subclass of Trampoline and implement it there.
But for the challenge:
Assuming this class:
<?php
class FancyMocking {
function doThing($value) { }
}
and that we have $x calls and one of those has to have a $value > 200:
<?php
class FancyMockingTest extends PHPUnit_Framework_TestCase {
public function testAtLeastOfMy200CallsShouldHaveAValueGreaterThan500() {
$maxInvocations = 200;
$mock = $this->getMock('FancyMocking');
$mock->expects($this->exactly($maxInvocations))
->method('doThing')
->with($this->callback(function ($value) use ($maxInvocations) {
static $invocationCount = 0;
static $maxValue = 0;
$maxValue = max($value, $maxValue);
/* The assertion function will be called twice by PHPUnit due to implementation details, so the *2 is a hack for now */
if (++$invocationCount == $maxInvocations * 2) {
$this->assertGreaterThan(200, $maxValue, 'in 500 tries the max value didn\'t to over 200');
}
return true;
}))
->will($this->returnCallback(function ($value) {
return $value >= 200;
}));
for($i = $maxInvocations - 2; $i; --$i) {
$mock->doThing(50);
}
var_dump($mock->doThing(250));
var_dump($mock->doThing(50));
}
}
This will produce:
PHPUnit 3.7.9 by Sebastian Bergmann.
.bool(true)
bool(false)
Time: 0 seconds, Memory: 2.75Mb
OK (1 test, 2 assertions)
Meaning the call with 250 returns true an the whole test case works.
If it fails:
To make it fail we change var_dump($mock->doThing(250)); to var_dump($mock->doThing(70)); and run it again:
PHPUnit 3.7.9 by Sebastian Bergmann.
Fbool(false)
Time: 0 seconds, Memory: 2.75Mb
There was 1 failure:
1) FancyMockingTest::testAtLeastOfMy200CallsShouldHaveAValueGreaterThan500
Expectation failed for method name is equal to <string:doThing> when invoked 200 time(s)
in 500 tries the max value didn't to over 200
Failed asserting that 70 is greater than 200.
.../FancyMockingTest.php:29
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
The solution that doesn't use PHPUnits mocking API would be something like
class FancyMockingFakeImplementation extends FancyMocking, using that instead of the mock and writing the custom logic there.

Matrix Combination Logic

NOTE: **Please read all other related questions:**
Here is my first and second attempts at asking this question:
Efficient way to determine the outcome of test matrix
Would cartesian product be the best approach for this
Here is the problem:
I have several ( like 20 ) Boolean validations ( true / false )
All Boolean validations as a whole also have a validation Result
I'm trying to find the best solution to test all the validations and also the validation result. I was looking into a Matrix to hold all possible combinations but that might be an overkill.
Here is an example ( 1 - 20 ):
test_1 = Has 30 Kills
test_2 = Has Found Map 1
test_3 = Has Mastered Level 1
test_4 = Has Achieved Grunt Status
test_5 = Has Assault weapon
test_6 = Has Knife
test_7 = Has Grenade
test_x = Etc...
So when the Player has all these validations as TRUE I can then give a level result
if test_1, test_2, test_3 ( any combination of the three ): level = green
All combinations are ( 15 ):
test_1
test_2
test_3
test_1, test_2
test_1, test_3
test_2, test_1 ( duplicate can skip this )
test_2, test_3
test_3, test_1 ( duplicate can skip this )
test_3, test_2 ( duplicate can skip this )
test_1, test_2, test_3
test_1, test_3, test_2 ( duplicate can skip this )
test_2, test_1, test_3 ( duplicate can skip this )
test_2, test_3, test_1 ( duplicate can skip this )
test_3, test_1, test_2 ( duplicate can skip this )
test_3, test_2, test_1 ( duplicate can skip this )
So unique combinations are ( 7 instead of 15 ):
test_1
test_2
test_3
test_1, test_2
test_1, test_3
test_2, test_3
test_1, test_2, test_3
Now I'm trying to find the best possible solution to find unique combinations for all 20 validations and come up with a level validation from that matrix.
UPDATE:
Also I need to find only TRUE Combinations so you might read the Unique Combinations like this:
test_1
test_2
test_3
test_1, test_2
test_1, test_3
test_2, test_3
test_1, test_2, test_3
Boolean Value Results from Validation Tests
TRUE, FALSE, FALSE
FALSE, TRUE, FALSE
FALSE, FALSE, TRUE
TRUE, TRUE, FALSE
TRUE, FALSE, TRUE
FALSE, TRUE, TRUE
TRUE, TRUE, TRUE
So any of these combinations would be a GREEN level.
Also I need to know the order of the test validations as well as the matrix order to compare for level assignment. So for GREEN level I only need the validation result combination matrix for test 1, 2 and 3. So I could ignore tests 4 - 20
UPDATE #2:
I know this looks like a simple OR condition but I wanted to take out the combination logic to set the level into a matrix. I could use the matrix of combinations to determine the level logic without having to code additional or modify current logic in the code itself. I wanted to just compare the validations results for a given set of tests and assign a level to those results. Different permutations of the validation combinations would result in different level assignments.
I understand that I could add the combination logic in the code itself, but as this logic looks to be very volatile and thought this might offer a more flexible solution.
Suggestions?
(removed my two previous answers for clarity)
After your last edit, instead of answering directly, I would like first to be sure to 100% understand the "level detection algorithm" you want.
If I understand well, you would like to define/maintain a simple configuration structure telling which tests give which level.
e.g. with an associative array:
array(
'green' => array('test1', 'test2', 'test3'),
'orange' => array('test2', 'test3', 'test5')
...
);
With the meaning: if one or more of the tests in the list are satisfied, assign that level (array key) to the player. Such logic could easily cover quite a lot of combinations, and would avoid handling a huge matrix.
Maybe you want to extend the logic to tell, for example, that at least N tests among the test list are satisfied.
array(
'green' => array(
'tests' => array('test1', 'test2', 'test3'),
'nb_required' => 2
),
...
);
Is that what you want?
BTW, why don't you use a classic XP/level up system? :-p
Not quite to answer your question, but it seems you're missing something.
Lets say you have twenty tests, labeled 1 though n. Decide for test n whether you want to validate for it, or not. Either you include the test for validation, or you don't. That's two choices for every test. Proceed through (n-1) until you have no more tests. For n=20, that's 2^20 = 1048576 possible combinations of tests (including one combination where you don't select any tests), which means 1048576 results. Now I still don't understand what you mean by "level of validation", but I have to wonder why you'd need that many combinations of tests in the first place.
Edit: Well, a test matrix (so to speak) could work.... but you'd still have to generate the matrix. You're likely not going to hand code all 1048576 combinations. But supposing you've already created the mapping, you just have a zero indexed array as a look up table with 1048576 values that you desire and you're done! All you would need to map the test results to the matrix would be assigning each test a binary digit (test1 would be the one's place, test2 would be the 2's place, etc.)
What I suspect you really want is a quick way to generate the mapping given some broader rules you might encode in php... but here's funny part about that. If you had some code that generated the matrix for any and every set of tests, the matrix is then superfluous; Your code is essentially a compressed representation for the matrix. The only point in using one over the other is whether or not one would be faster than the other.
It also seems you really don't care about all 1048576 combinations. I suspect it might benefit you to partition your tests into their own set of tests (one for red, one for blue, etc). For instance, if you partition tests into groups of 5, and there is, oh, 3 different possibilities (instead of 16) for each group, you're only working with (3 different results per group)^(4 groups) = 81 unique results. Eighty one unique results is much more manageable than over a million.
It seems you may also need different partitions for different independent things. It also may not matter even which tests result in true as long as a certain number of them are true, that is "goal: 3 out of 5 blue objectives met" "goal: 7 out of 10 red and blue objectives met" or whatever. Those tests would have to be accessed independently and they wouldn't necessarily be multiplicative with the results of the other tests-- there will never be 7 out of 10 red and blue objectives met if none of your blue objectives are met (I'll admit, this is hard to explain further without an example).
So, really, there's no quick answer. Either you deal with all and every one of the 1048576 combinations individually, or you create and encode some sort of generic grouping scheme for your tests to drastically cut down on combinations. You can certainly create your full matrix scheme by said scheme, and maybe even dynamically generate your full 1048576 element matrix for a given set of combinations. But you cannot burn a whole candle by only burning half of it.
Edit II (and III):
I'm going to make one more guess. The levels you've proposed seem to be related to the number of objectives completed per each (and previous batch). So encode your results in to a string of ("T", and "F") and count the "F"s for each batch and determine from there. If the count of Fs is the number of characters in the string, no objective of the batch is completed, if the number of Fs is zero, all objectives of the batch are completed.
Lets say the batch after blue is purple. Could somebody achieve a goal in purple without completing all the green batch? If so, you have another color to assign for that possibility; if not, then, I would assume that these levels are ordered (orange between green and blue, maybe "brown" or something between blue and purple--you can tell I pulled this out of thin air-- and it should be fairly simple to cascade through these counts to determine the current "level".
If there is no ordering, then it's quite analogous to the situation I mentioned above: Each group has a result { "no objectives completed", "some objectives completed", "all objectives completed"}. There are x groups which means 3^x possible results. You should be basing your level matrix on these results, not the results of the tests previously mentioned.
Introduction
You can easy get combinations like this :
echo "<pre>";
$test = ["test_1","test_2","test_3"];
// Get Combination
$return = uniqueCombination($test);
//Sort
sort($return);
//Pretty Print
print_r(array_map(function($v){ return implode(",", $v); }, $return));
function uniqueCombination($in, $minLength = 1, $max = 10) {
$count = count($in);
$members = pow(2, $count);
$return = array();
for($i = 0; $i < $members; $i ++) {
$b = sprintf("%0" . $count . "b", $i);
$out = array();
for($j = 0; $j < $count; $j ++)
$b{$j} == '1' and $out[] = $in[$j];
count($out) >= $minLength && count($out) <= $max and $return[] = $out;
}
return $return;
}
Output
Array
(
[0] => test_1
[1] => test_2
[2] => test_3
[3] => test_1,test_2
[4] => test_1,test_3
[5] => test_2,test_3
[6] => test_1,test_2,test_3
)
The Problem
They are about 1,048,576 combination and i believe this is not the kind of array you want i would suggest a condition based combination rather than all possible combination
Example
// Game Conditions
$game = new Game();
$game->addCondition(new Condition(new Level(1), new Kill(30)));
$game->addCondition(new Condition(new Level(2), new Map(1), new Kill(10)));
$game->addCondition(new Condition(new Level(3), new Grunt(10)));
$game->addCondition(new Condition(new Level(4), new Knife(1), new Ak47(1)));
$game->addCondition(new Condition(new Level(5), new Grenade(1), new Combo(7)));
$game->addCondition(new Condition(new Level(6), new Kill(100), new Blow(10), new Stab(10)));
$game->addCondition(new Condition(new Level(7), new Herb(10), new Medipack(1), new Map(1), new Artwork(1)));
$game->addCondition(new Condition(new Level(8), new Grenade(20),new Artwork(5)));
// User Starts Game
$user = new User($game);
$user->task(new Map(1));
$user->task(new Herb(5));
$user->task(new Kill(10));
$user->task(new Kill(10));
$user->task(new Herb(10));
$user->task(new Kill(10));
$user->task(new Kill(10));
$user->task(new Ak47(1));
$user->task(new Knife(1));
$user->task(new Map(1));
$user->task(new Grunt(17));
$user->task(new Kill(60));
$user->task(new Combo(1));
$user->task(new Kill(40));
$user->task(new Medipack(1));
$user->task(new Artwork(1));
$user->task(new Grenade(1));
$user->task(new Combo(10));
$user->task(new Blow(10));
$user->task(new Stab(5));
$user->task(new Blow(10));
$user->task(new Stab(5));
$user->task(new Stab(5));
printf("\n<b>Total Point %s",number_format($user->getPoint(),0));
Output
+Task Map Added (1)
+Task Herb Added (5)
+Task Kill Added (10)
^Task Kill Updated (20)
^Task Herb Updated (15)
^Task Kill Updated (30)
*Level 1 Completed*
*Level 2 Completed*
^Task Kill Updated (40)
+Task Ak47 Added (1)
+Task Knife Added (1)
^Task Map Updated (2)
+Task Grunt Added (17)
*Level 3 Completed*
*Level 4 Completed*
^Task Kill Updated (100)
+Task Combo Added (1)
^Task Kill Updated (140)
+Task Medipack Added (1)
+Task Artwork Added (1)
+Task Grenade Added (1)
^Task Combo Updated (11)
*Level 5 Completed*
+Task Blow Added (10)
+Task Stab Added (5)
^Task Blow Updated (20)
^Task Stab Updated (10)
*Level 6 Completed*
*Level 7 Completed*
^Task Stab Updated (15)
<b>Total Point 1,280</b>
Classes Used
class Task {
private $no;
function __construct($no = 1) {
$this->no = $no;
}
function getNo() {
return $this->no;
}
function getName() {
return get_called_class();
}
function merge(Task $task) {
$this->no += $task->getNo();
return $this;
}
}
class User {
private $game;
private $point;
private $tasks = array();
function __construct(Game $game) {
$this->game = $game;
}
function getPoint() {
return $this->point;
}
function getTask() {
return $this->tasks;
}
function task(Task $task) {
if (isset($this->tasks[$task->getName()])) {
$this->tasks[$task->getName()]->merge($task);
printf("^Task %s \tUpdated (%s)\n", $this->tasks[$task->getName()]->getName(), $this->tasks[$task->getName()]->getNo());
} else {
printf("+Task %s \tAdded (%s)\n", $task->getName(), $task->getNo());
$this->tasks[$task->getName()] = $task;
}
$this->point += $task->getNo() * $task->d;
$this->game->notify($this);
}
}
class Condition {
private $task = array();
private $status = false;
function __construct(Level $level) {
$this->level = $level;
$tasks = func_get_args();
array_shift($tasks);
$this->task = new SplObjectStorage($tasks);
foreach ( $tasks as $task )
$this->task->attach($task);
}
function update(Game $game, User $user) {
if ($this->status)
return;
$n = 0;
foreach ( $this->task as $cTask ) {
foreach ( $user->getTask() as $task ) {
if ($cTask->getName() == $task->getName()) {
if ($task->getNo() >= $cTask->getNo())
$n ++;
}
}
}
if ($n === count($this->task) && ($game->getLevel()->getNo() + 1) == $this->level->getNo()) {
$this->status = true;
$game->setLevel($this->level);
printf("\n*Level %d Completed* \n\n", $this->level->getNo());
}
}
function getStatus() {
return $this->status;
}
}
class Game {
private $taskCondition;
private $level;
public function __construct() {
$this->taskCondition = new SplObjectStorage();
$this->level = new Level(0);
}
function setLevel(Level $level) {
$this->level = $level;
}
function getLevel() {
return $this->level;
}
function addCondition($condition) {
$this->taskCondition->attach($condition);
}
public function notify($user) {
foreach ( $this->taskCondition as $conditions ) {
if ($conditions->getStatus() === true) {
// detached completed condition
$this->taskCondition->detach($conditions);
continue;
}
$conditions->update($this, $user);
}
}
public function hasCondition() {
return count($this->taskCondition);
}
}
class Level extends Task{}
class Action extends Task{};
class Weporn extends Task{};
class Skill extends Task{};
class Tresure extends Task{};
class Medicine extends Task{};
class Kill extends Action{public $d = 5 ;};
class Blow extends Action{public $d = 7 ;};
class Stab extends Action{public $d = 10 ;};
class Map extends Tresure{public $d = 10 ;};
class Artwork extends Tresure{public $d = 20 ;};
class Knife extends Weporn{public $d = 5 ;};
class Grenade extends Weporn{public $d = 10 ;};
class Ak47 extends Weporn{public $d = 10 ;};
class Jump extends Skill{public $d = 2 ;};
class Grunt extends Skill{public $d = 4 ;};
class Combo extends Skill{public $d = 7 ;};
class Medipack extends Medicine{public $d = 5 ;};
class Herb extends Medicine{public $d = 5 ;};
Simple Online Demo
I have found the graphic display of your question as you mentioned.
|0|1|2|3|4|5|6|7|8|9|
|1|T|T|T|T|T|T|T|T|T|
|2|F|T|T|T|T|T|T|T|T|
|3|F|F|T|T|T|T|T|T|T|
|4|F|F|F|T|T|T|T|T|T|
|5|F|F|F|F|T|T|T|T|T|
|6|F|F|F|F|F|T|T|T|T|
|7|F|F|F|F|F|F|T|T|T|=>[7,9] if this is the answer
|8|F|F|F|F|F|F|F|T|T|
|9|F|F|F|F|F|F|F|F|T|
In my opinion you should check the conditions in reverse diagonal order, then left to right.
That means
first check [9,9]
if it fails check [8,8]
if this fails check [7,7]
if it gives true check [7,8]
if this gives false check [7,9] this must be the answer and the simple shortcut,
This method will reduce over all process time.

php class function not returning properly to caller

Background
I am writing a new database connector file for TeraWURFL which will use PDO extension. For more details on this please check
Details
I added a new database connector - TeraWurflDatabase_MySQL5_Mine.php and defined the same in the config file - TeraWurflConfig.php (there already are many connector files which come with TeraWURFL the value in the config file decides which one is used) -
public static $DB_CONNECTOR = "MySQL5_Mine";
I then wrote a test script to unit test all the functions of the new TeraWurflDatabase_MySQL5_Mine.php class file to make sure they return the same values after the changes. I am facing problem in the test script.
Everything is working fine but something is wrong with one function inside TeraWurflDatabase_MySQL5_Mine.php called rebuildCacheTable(). When I call this function from my test script, control does not return back to my test script after the return statement inside that function. -
Code inside test script test_connector.php -
/*file inclusiong start*/
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/TeraWurfl.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/TeraWurflConfig.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/DatabaseConnectors/TeraWurflDatabase.php'; //this file is same on both setups
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/TeraWurflLoader.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/UserAgentFactory.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/UserAgentUtils.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/WurflConstants.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/WurflSupport.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/UserAgentMatchers/UserAgentMatcher.php';
require_once '/var/cake_1.2.0.6311-beta/app/webroot/Tera-Wurfl_PDO/DatabaseConnectors/TeraWurflDatabase_MySQL5_Mine.php';
/*file inclusiong end*/
$wurflDbPdoObj = new TeraWurflDatabase_MySQL5_Mine();
$wurflDbPdoObj->connect();
$dbObj = $wurflDbPdoObj;
echo "before call";
var_dump($dbObj->rebuildCacheTable());
echo "after call"; //this does not execute if new TeraWurfl() object is initiated below
And code inside TeraWurflDatabase_MySQL5_Mine -
class TeraWurflDatabase_MySQL5_Mine extends TeraWurflDatabase{
...
...
public function rebuildCacheTable(){
$rebuilder = new TeraWurfl(); //if this object is initiated, return does not happen properly
return true; //this does not return properly.
}
}
My debugging so far
I verified that the object initiated by $rebuilder = new TeraWurfl(); is a proper object.
I could narrow down to this, that if the line $rebuilder = new TeraWurfl(); inside TeraWurflDatabase_MySQL5_Mine is removed, return works properly.
Also, there is no such problem if I call the same function of the existing connector class TeraWurflDatabase_MySQL5 (I include TeraWurflDatabase_MySQL5.php instead of TeraWurflDatabase_MySQL5_Mine.php in the file inclusion part and make public static $DB_CONNECTOR = "MySQL5";) -
$wurflDbPdoObj = new TeraWurflDatabase_MySQL5();
$wurflDbPdoObj->connect();
$dbObj = $wurflDbPdoObj;
echo "before call";
var_dump($dbObj->rebuildCacheTable());
echo "after call"; //works
I also compared the var_dump() values of the objects created by $rebuilder = new TeraWurfl(); in both these cases (new TeraWurflDatabase_MySQL5_mine.php and existing TeraWurflDatabase_MySQL5.php). Found no problem there.
I have no clue what is wrong with my code. Any idea??
Updates
Further found that the problem is inside the constructor of the TeraWurfl.php class. The constructor initiates an object of the database connector class again -
public function __construct()
{
...
$dbconnector = 'TeraWurflDatabase_'.TeraWurflConfig::$DB_CONNECTOR; //return fails if this object is initiated
if($this->db === false) $this->db = new $dbconnector;
...
}
No errors/warnings appear and var_dump() looks fine comparing with the existing database connector case. There too an object of that database connector class is initiated.
Update #2 - profiling output
I set up code profiling by following steps as mentioned in http://kpayne.me/2012/02/04/use-register_tick_function-to-profile-your-code/ with a little modification to also display the class name in the output, and here are the outputs -
Profiling on test script for TeraWurflDatabase_MySQL5_Mine -
Array
(
[TeraWurfl ->__construct] => Array
(
[time] => 9.0599060058594E-5
[calls] => 8
)
[TeraWurflDatabase_MySQL5_Mine ->__construct] => Array
(
[time] => 4.3630599975586E-5
[calls] => 4
)
[TeraWurflDatabase_MySQL5_Mine ->connect] => Array
(
[time] => 0.00010228157043457
[calls] => 6
)
[TeraWurflDatabase_MySQL5_Mine ->rebuildCacheTable] => Array
(
[time] => 7.8678131103516E-6
[calls] => 1
)
[show_profile] => Array
(
[time] => 1.7881393432617E-5
[calls] => 1
)
)
But for the existing class TeraWurflDatabase_MySQL5, I did not get the function call details, which is strange again -
Array
(
[show_profile] => Array
(
[time] => 0.00024199485778809
[calls] => 1
)
)
In such cases you can debug the flow even without xdebug by using:
declare(ticks=1);
register_tick_function(function(){
$debug = debug_backtrace();
echo "Running on line " . $debug[0]['line'] . " in file " . $debug[0]['file'] . "\n";
});
Edit:
Actually, my example was bad, so I only left the important part.

Categories