Passing multiple variables to a Gearman worker function - php

How do you pass two variables to the same worker function? For example, say I wished to concat two strings that I pass from the client. I saw in some example code an array being used, but I can't get it to work.
<?php
$client= new GearmanClient();
$client->addServer();
$arguments = array(
"string1" => "hey",
"string2" => "there"
);
$client->addTask("string_concat", $arguments);
$client->runTasks();
?>
This tells me it's an invalid workload however (I assume cause it's an array being passed). How should I be passing them - should I create a task for each?
Then if I can't send an array, how can I use multiple variables in the worker function. I've tried like function String_Concat($job, $job2) but then I'm not sure how I'd add them to the workload()
Here is some example code if I were able to pass arrays:
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("string_concat", "String_Concat");
while ($worker->work());
function String_Concat($job)
{
$arguments = $job->workload();
return $arguments["string1"] . $arguments["string2"];
}
?>
What's the best way to do this? Thanks a lot!

You should serialize it.
Something like:
$data = serialize( $array );
$client->addTask("string_concat", $data);
Then, from your worker, you could do something like...
if (is_string($data) && $data = unserialize($workload)) {
} else {
// Maybe throw Exception or something?
}

Related

PHP Gearman tasks not returning jobHandle

We're using Gearman and when do use methods like doLowBackground or doHigh, these all return a jobHandle, but when we do tasks there is no jobHandle object. We get the GearmanTask object, instead of getting the jobHandle, we get string(0) ""
Any ideas what could cause this?
Thank you!
EDIT: Here is the code and additional info:
// $client = \GearmanClient; // servers added, all that jazz
// $workload = 'string';
$arguments = array(
'handleJob',
$workload
);
$task = call_user_func_array(array($client, $method), $arguments);
if ($task instanceof GearmanTask) {
$handles[] = $task->jobHandle();
}
$data = $client->runTasks();
The tasks run correctly but $handle is being populated with empty strings (one for each task added)
EDIT: This is the response we get:
object(GearmanTask)#294 (0) {
}
I've dumped every PECL gearman object, nothing ever displays, here's the client, populated with servers, options, etc
object(GearmanClient)#291 (0) {
}
Doesn't show anything.
A job handle is not assigned to a task until the task is received and queued by the Gearman job server.
However, you can use GearmanClient::setCreatedCallback() to get the handle once it has been queued. This must be done before both adding and running the tasks:
$client = new \GearmanClient();
$client->addServer('127.0.0.1');
$handles = array();
$client->setCreatedCallback(function (\GearmanTask $task) use (&$handles) {
$handles[] = $task->jobHandle();
});
$client->addTask('functionName', 'workload'); // ...
$client->runTasks();

multiple return statements at once?

I am trying to develop a chat bot.
I have a doubt regarding the functionality.
Here's a part of the code:
<?php
require_once 'bootstrap.php';
require_once CB_HOME.'/library/CommonFunctions.php';
class testBot extends AbstractCbRest{
public function subscriptionCreated($userName){
return "Welcome ";
}
public function subscriptionDeleted($userName){
return "Thanks ";
}
public function messageReceived($from, $message){
return "" ; // how to return multiple here
}
In the messageReceived function ,I am going to implement the chatbot functionality.
Whenever i get a message from the user i am going to return something.For that i will have to run some php scripts and make some api calls.The final result i will send to the user.
All this is going to take approximately 20-25 seconds.
Is there a way I can send multiple return statements?
Like while the Api calls are being made i can send a message to the user and then wait for the actual result to come and then send it?
I cannot think of a way because as soon i sent a message,i cannot return something until and unless user replies with something.
Use an array :
public function messageReceived($from, $message){
return array(
'Welcome',
'Thanks',
'Hello',
'Whatever'
);
}
Or even an associative array
array(
'msg1' => 'Welcome',
'msg2' => 'Thanks',
'msg3' => 'Hello',
'msg4' => 'Whathever'
)
Then you can use a particular message with :
array['msg1']
You could create an array and return that :
public function messageReceived($from, $message){
$retval = array();
$retval[] = "message1";
$retval[] = "message2";
return $retval;
}
or
public function messageReceived($from, $message){
return array("message1","message2");
}
It sounds like you need to think about using AJAX rather than making synchronous calls while the page rendering is being processed.

Run a method if it has not already ran with the current class?

I have a class that I am writing and I have a method that I would like to run once per initiation of the class. Normally this would go in the construct method, but I only need it to run when I call certain methods, not all.
How would you all recommend I accomplish this?
Create a private property $methodHasBeenRun which has a defualt value of FALSE, and set it to TRUE in the method. At the start of the method, do:
if ($this->methodHasBeenRun) return;
$this->methodHasBeenRun = TRUE;
You didn't specify exactly why you only want to run a given method once when certain methods are called, but I am going to make a guess that you're loading or initializing something (perhaps data that comes from a DB), and you don't need to waste cycles each time.
#DaveRandom provided a great answer that will work for sure. Here is another way you can do it:
class foo {
protected function loadOnce() {
// This will be initialied only once to NULL
static $cache = NULL;
// If the data === NULL, load it
if($cache === NULL) {
echo "loading data...\n";
$cache = array(
'key1' => 'key1 data',
'key2' => 'key2 data',
'key3' => 'key3 data'
);
}
// Return the data
return $cache;
}
// Use the data given a key
public function bar($key) {
$data = $this->loadOnce();
echo $data[$key] . "\n";
}
}
$obj = new foo();
// Notice "loading data" only prints one time
$obj->bar('key1');
$obj->bar('key2');
$obj->bar('key3');
The reason this works is that you declare your cache variable as static. There are several different ways to do this as well. You could make that a member variable of the class, etc.
I would recommend this version
class example {
function __construct($run_magic = false) {
if($run_magic == true) {
//Run your method which you want to call at initializing
}
//Your normale code
}
}
so if you do not want to run it create the class like
new example();
if you want
new example(true);

Autocreate object when property is called

Im wondering if there is a way to autocreate object if a property is called. An example:
<?php
echo $myObj->myProperty
?>
This code will of course fail because i did not initiate $myObj before reading the property.
What im looking for is a way to automaticly initiate $myObj based on "myObj".
Something like:
<?php
class myObj {
public myProperty = 'BlaBla';
}
echo $myObj->myProperty; //outputs BlaBla instead of failing
?>
I know about __autoload($classname) but that only works of initiating classcode with i.e. an include(), so that is not what im after.
You can use magic methods to automate stuff like that...
http://www.php.net/manual/en/language.oop5.magic.php
Just to close this question, this is what i ended up doing:
preg_match_all("/\\\$(.*?)->/si", $code, $matches);
I loop trough the code i get from database looking for any references to objects like
$xxxx->
Then i loop trough the references and create the objects
foreach($matches[1] as $key=>$value) {
$$value = Connector::loadConnector($value);
}
Where the "loadConnector is:
public function loadConnector($connector, $params = NULL) {
require_once $connector. ".php";
$c_name = $connector;
return new $c_name($params);
}
This is of course based on my file structure and it also needs some errorhandling, but so far it looks like it solves my problem :)
BR/Sune

Create an HttpRequest from environment

Can I get a HttpRequest automatically created from the environment? In other words, right now it seems like you have to...
$request = new HttpRequest;
$request->setCookies($_COOKIE);
$request->setHeaders(apache_request_headers());
$request->setPostFields($_POST);
$request->setQueryData($_GET);
$request->setRawPostData(file_get_contents('php://input'));
$request->setUrl($_SERVER['REQUEST_URI'']);
We also need to set the method -- a ridiculous chore, since $_SERVER['REQUEST_METHOD'] is a string and HttpRequest::setMethod takes an int in the HTTP_METH_* series of contants. So you have to set up your own mapping.
I want to like HttpRequest, but it seems cumbersome to use at the moment. I hope I'm missing something.
Edit:
The idea is to make testing cleaner. $_COOKIE and friends are superglobals. How do you test that?
function receiveRequest() {
$code = 'that touches superglobals like' . $_COOKIE['example'];
$response = new HttpResponse;
$response->setStatus(200);
return $response;
}
function testServer() {
$oldCookie = $_COOKIE;
$oldPost = $_POST;
// etc...
$_COOKIE = array('example' => 'stuff');
$_POST = array();
// etc...
$response = receiveRequest();
$_COOKIE = $oldCookie;
$_POST = $oldPost;
// etc...
assert($response->getStatus() === 200);
}
You need to control the state of not just what you use -- $_COOKIE in this example -- but every superglobal. There are about a dozen. It would be a lot cleaner to wrap up all that stuff in HttpRequest.
function receiveRequest(HttpRequest $request) {
$code = 'is purely a function of arguments like' . $request->getCookie('example');
$response = new HttpResponse;
$response->setStatus(200);
return $response;
}
function testServer() {
$request = new HttpRequest;
$request->setCookie('example' => 'stuff');
$response = receiveRequest($request);
assert($response->getStatus() === 200);
}
Then my actual server.php would use the hypothetical static method that I'm looking for.
$request = HttpRequest::generateRequestFromEnvironment($_COOKIE, $_POST, ...);
unset($_COOKIE, $_POST, ...);
$response = receiveRequest($request);
$response->send();
This seems to me like an odd use case - you want to create an HttpRequest to...yourself? Using exactly the parameters you were passed? Why?
The normal case is for requesting another resource, from another host, for which the kind of "automatic setup" you desire is pretty useless. If you really need this situation, it seems trivial to wrap this in a function that's easily reused?
From what you've posted, I think you're using HttpRequest as a container for all the information about the request which triggered your script.
This isn't what it is for - it is for making HTTP requests to other services from within your script. For example, you might request data from the Flickr API

Categories