safe storage of data. I read that for this task suits Stackable.
I inherit Stackable but data in storage is not synchronized.
AsyncOperation -- just incrementing value in storage
AsyncWatcher -- just making echo of value in storage.
Problem : data in storage is not modifying from AsyncOperation thread, storage permanently contains a -1.
I'm using pthreads.
class Storage extends Stackable {
public function __construct($data) {
$this->local = $data;
}
public function run()
{
}
public function getData() { return $this->local; }
}
class AsyncOperation extends Thread {
private $arg;
public function __construct(Storage $param){
$this->arg = $param->getData();
}
public function run(){
while (true) {
$this->arg++;
sleep(1);
}
}
}
class AsyncWatcher extends Thread {
public function __construct(Storage $param){
$this->storage = $param -> getData();
}
public function run(){
while (true) {
echo "In storage ". $this->storage ."\n";
sleep(1);
}
}
}
$storage = new Storage(-1);
$thread = new AsyncOperation($storage);
$thread->start();
$watcher = new AsyncWatcher($storage);
$watcher->start();
As you can see, Stackable class has a lot of methods, mainly used for async operations and they can help you with your issue. You should modify your async classes in this way:
class AsyncOperation extends Thread {
private $arg;
public function __construct(Storage $param){
$this->arg = $param->getData();
}
public function run(){
while (true) {
$this->arg++;
sleep(1);
}
$this->synchronized(function($thread){
$thread->notify();
}, $this);
}
}
and their usage will be like this:
$storage = new Storage();
$asyncOp = new AsyncOperation($storage);
$asyncOp->start();
$asyncOp->synchronized(function($thread){
$thread->wait();
}, $asyncOp);
var_dump($storage);
Related
I'm using php-zts to perform parallel data processing, using symfony 4 and PThreads
I'm great at running multiple threads, but I'm facing a problem, I need each of the threads to be able to work with doctrine
I need to make sure that each thread is able to work with doctrine
I tried to transfer a container instance directly, but it won't work because it can't be sterilized
/console_comand.php
private function gettingStatistics(){
$pool = new \Pool(4, Autoloader::class, ["vendor/autoload.php"]);
$store = new \Threaded();
$class = new Meta();
$pool->submit(new Task($class,$store));
$pool->collect();
$pool->shutdown();
$listQuotes = array();
foreach ($store as $obj){
foreach ($obj->{'response'} as $exchange => $data){
$listQuotes[$exchange] = $data;
}
}
unset($store);
unset($interface);
return $listQuotes;
}
/Autoloader.php
<?php
namespace App\Worker;
class Autoloader extends \Worker
{
protected $loader;
public function __construct($loader)
{
$this->loader = $loader;
}
/* включить автозагрузчик для задач */
public function run()
{
require_once($this->loader);
}
/* переопределить поведение наследования по умолчанию для нового потокового контекста */
public function start(int $options = PTHREADS_INHERIT_ALL)
{
return parent::start(PTHREADS_INHERIT_NONE);
}
}
/Autoloadable.php
<?php
namespace App\Worker;
/* нормальный, автоматически загруженный класс */
class Autoloadable
{
public $response;
public function __construct($greeting)
{
$this->response = $greeting->job();
}
}
/Task.php
<?php
namespace App\Worker;
class Task extends \Threaded
{
protected $greeting;
protected $result;
public function __construct($greeting,\Threaded $store)
{
$this->greeting = $greeting;
$this->result = $store;
}
public function run()
{
$greeting = new Autoloadable($this->greeting);
$this->result[] = $greeting;
}
}
how do I pass the right doctrine to be able to work with it from the job?
there's a very similar question on github but I can't deal with it.
https://github.com/krakjoe/pthreads/issues/369
Have you tried requiring an ObjectManager instance in the __construct of Task (your last code block)?
Have a read of this article
Cannot test it atm, don't have zts setup, but I've used this to great success in other projects.
I would expect you need to do something like:
$pool = new Pool(4);
for ($i = 0; $i < 15; ++$i) {
$pool->submit(new class($objectManager) extends \Threaded
{
private $objectManager;
public function __construct(ObjectManager $objectManager)
{
$this->objectManager= $objectManager;
}
public function run()
{
// obviously replace the contents of this function
$this->objectManager->performTask;
echo 'Job\'s done.' . PHP_EOL;
}
});
}
while ($pool->collect());
$pool->shutdown();
The instantiation of the new anonymous class takes the $objectManager present in your current instance, like /console_comand.php there, and passes it to this new anonymous class to fulfill the __construct requirements.
The linked article does a better job of explaining it than I do, so please give it a read.
I have a class that is using the State pattern. Here's a simple example
/**
* #Enitity
**/
class Door
{
protected $id;
protected $state;
public function __construct($id, DoorState $state)
public function setState(DoorState $state)
{
$this->state = $state;
}
public function close()
{
$this->setState($this->state->close())
}
...
}
interface DoorState
{
public function close;
public function open;
public function lock;
public function unlock;
}
class DoorAction implements DoorState
{
public function close()
{
throw new DoorError();
}
...
}
then several classes that define the appropriate actions in the states
class OpenedDoor extends DoorAction
{
public function close()
{
return new ClosedDoor();
}
}
So I would have some thing like
$door = new Door('1', new OpenedDoor());
DoctrineDoorRepository::save($door);
$door->close();
DoctrineDoorRepository::save($door);
How would I implement the mapping in Doctrine so I can persist it?
I'm hung up on the $state property. I would like to save the whole DoorAction based object but do I have to the map the DoorAction super class or each individual sub class?
I've looked at implementing it using Embeddable or SuperMapping but run into problems with each.
Doctrine2 DBAL has a feature in the documentation that allows ENUM's
https://www.doctrine-project.org/projects/doctrine-orm/en/current/cookbook/mysql-enums.html#mysql-enums
When we take the Solution 2: Defining a Type as a base, one could create an own type, for instance called doorstatetype or similar to represent the open/closed state. For instance like this:
<?php
namespace Acme\Model\Door;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class DoorStateType extends Type
{
const ENUM_DOORSTATE = 'enumdoorstate';
const STATE_OPEN = 'open';
const STATE_CLOSED = 'closed';
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return "ENUM('" . self::STATE_OPEN . "', '" . self::STATE_CLOSED . "') COMMENT '(DC2Type:" . ENUM_DOORSTATE . ")'";
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (!in_array($value, array(self::STATE_OPEN, self::STATE_CLOSED))) {
throw new \InvalidArgumentException("Invalid state");
}
return $value;
}
public function getName()
{
return self::ENUM_DOORSTATE;
}
}
And then use it like this:
<?php
namespace Acme\Model\Door;
/** #Entity */
class Door
{
/** #Column(type="enumdoorstate") */
private $state;
public function open()
{
if (!DoorStateType::STATE_OPEN === $this->state) {
throw new \LogicException('Cannot open an already open door');
}
$this->state = DoorStateType::STATE_OPEN;
}
public function close()
{
if (!DoorStateType::STATE_CLOSED === $this->state) {
throw new \LogicException('Cannot close an already closed door');
}
$this->state = DoorStateType::STATE_CLOSED;
}
}
This allows searching for states:
$openDoors = $repository->findBy(array('state' => DoorStateType::STATE_OPEN));
You could basically then have the convertToPHPValue method create objects of the desired states that allow for some logic, like checking if an open door can be locked or similar.
In the case where the state has to be a class that contains logic, you could implement it like this:
First we define a normal state from which we can inherit:
<?php
namespace Acme\Model\Door;
abstract class DoorState
{
// Those methods define default behaviour for when something isn't possible
public function open()
{
throw new \LogicException('Cannot open door');
}
public function close()
{
throw new \LogicException('Cannot close door');
}
abstract public function getStateName();
}
Then the OpenState:
<?php
namespace Acme\Model\Door;
class OpenState extends DoorState
{
const STATE = 'open';
public function close()
{
return new ClosedState();
}
public function getStateName()
{
return self::STATE;
}
// More logic
}
And finally the ClosedState:
<?php
namespace Acme\Model\Door;
class ClosedState extends DoorState
{
const STATE = 'closed';
public function open()
{
return new OpenState();
}
public function getStateName()
{
return self::STATE;
}
// More logic
}
We can then, for persistence, simply use different convert methods:
<?php
namespace Acme\Model\Door;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
class DoorStateType extends Type
{
// SQL declarations etc.
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === OpenState::STATE) {
return new OpenState();
}
if ($value === ClosedState::STATE) {
return new ClosedState();
}
throw new \Exception(sprintf('Unknown state "%s", expected one of "%s"', $value, implode('", "', [OpenState::STATE, ClosedState::STATE])));
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->getStateName();
}
}
What if you map state as a string and then:
public function setState(DoorState $state)
{
$this->state = serialize($state);
}
and:
private function state()
{
return unserialize($this->state);
}
public function close()
{
$this->setState($this->state()->close())
}
It doesn't save my changes after adding a category.
If I add a category, it is seen in the overview, but if I refresh I see the original amount.
I guess there is an error in my Singleton-design but I can't seem to find it.
class ProductService {
private $_database;
public function __construct($databaseType) {
$databaseFactory = new DatabaseFactory();
$this->_database = $databaseFactory->createDatabase($databaseType);
}
public function addCategory($category){
$this->_database->addCategory($category);
}
public function getAllCategories() {
return $this->_database->getAllCategories();
}
}
class DatabaseFactory {
public function __construct() {
}
public function createDatabase($type){
switch ($type) {
case "Memory" :
return MemoryDatabase::getInstance();
}
}
}
class MemoryDatabase {
private $categories;
private function __construct() {
$this->categories = array(
new Category("Cheese"),
);
}
public static function getInstance() {
static $inst = null;
if ($inst === null) {
$inst = new MemoryDatabase();
}
return $inst;
}
private function __clone() {}
private function __wakeup() {}
public function addCategory($category) {
array_push($this->categories, $category);
}
public function getAllCategories() {
return $this->categories;
}
}
Each request you perform in PHP is stateless.
If you want to persist data between requests, you will need to put your data in some form of persistant storage, i.e., sessions, filesystem, database, memory, etc.
Singleton pattern only ensures a single copy of an object is created, for a given request.
I'm writing a wrapper (Adapter pattern) for a number of REST calls. I'm trying to decide how much my response object should be able to do.
class Job
{
private $xml;
public function __construct(SimpleXMLElement $xml)
{
$this->xml = $xml;
}
public function getName()
{
return $this->xml->Name;
}
public function getId()
{
return $this->xml->ID;
}
...
...
...
}
class RESTManager
{
private $client;
public function __construct(Guzzle $client)
{
$this->client = $client
}
public function getJobByName($name)
{
$job = $this->client->get('/query/job/' . $name);
return new Job($job->asXMLObj())
}
}
So I have something similar to the above. Once I have the Job object I will want to get some additional information such as, a list of items in the Job. This requires another server call
Should I ask the Job what the items are
class Job {
private $manager;
...
...
public function addManager(RESTManager $manager)
{
$this->manager = $manager;
}
public function getItems()
{
return $this->manager->getJobItems($this);
}
}
or
ask the RESTManager directly?
class RESTManager {
...
...
public function getJobItems(Job $job)
{
return $this->client->get('/job/' . $job->getId() . '/items');
}
}
I have the following PHP code as chain of resposibility, I am using PHP5.4.9.
abstract class Logger
{
protected $next;
public function next($next)
{
$this->next = $next;
return $this->next;
}
public function run(){
$this->invoke();
if(null!=$this->next){
$this->next->invoke();
}
}
abstract public function invoke();
}
class EmailLogger extends Logger
{
public function invoke()
{
print_r("email\n");
}
}
class DatabaseLogger extends Logger
{
public function invoke()
{
print_r("database\n");
}
}
class FileLogger extends Logger
{
public function invoke()
{
print_r("file \n");
}
}
$logger = new EmailLogger();
$logger->next(new DatabaseLogger())->next(new FileLogger());
$logger->run();
the expect output is:
email
database
file
but the actually output:
email
database
I hope to implement chain of resposibility design pattern by PHP language, one abstract class and three or more classes to do something as a chain. but only the first two object works.
Anyting missing? Or PHP can not use this coding style under PHP5.4.9?
Thanks.
Replace
public function run() {
$this->invoke ();
if (null != $this->next) {
$this->next->invoke();
}
}
With
public function run() {
$this->invoke ();
if (null != $this->next) {
$this->next->run ();
}
}
please try $this->next->invoke() change $this->next->run()