Completed
Push — master ( 094d27...3dcc20 )
by Benjamin
02:16
created

Agent::__destruct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace CurlX;
4
5
/**
6
 * Class Agent
7
 * @package CurlX
8
 *
9
 * @property int $max_concurrent The maximum number of simultaneous connections allowed
10
 * @property int $maxConcurrent The maximum number of simultaneous connections allowed
11
 * @property string $url default url for requests
12
 * @property array $post array of default post data for requests
13
 * @property float $time running time of the agent
14
 * @property int $timeout default timeout (in msec) for requests
15
 * @property array $options default cUrl options for requests
16
 * @property array $headers default headers for requests
17
 * @property resource $handle cUrl Multi Handle
18
 * @property callable[] $listeners array of registered listeners which will be registered to newly created requests
19
 * @property array $response responses of the individual requests
20
 */
21
class Agent
22
{
23
    /**
24
     * @var array results
25
     */
26
    protected $result;
27
28
    /**
29
     * @var array responses
30
     */
31
    protected $response;
32
33
    /**
34
     * @var int The maximum number of simultaneous connections allowed
35
     */
36
    protected $maxConcurrent = 0;
37
38
    /**
39
     * @var RequestInterface[] array of Requests
40
     */
41
    protected $requests;
42
43
    /**
44
     * @var Request default request
45
     */
46
    protected $defaultRequest;
47
48
    /**
49
     * @var resource cUrl Multi Handle
50
     */
51
    protected $mh;
52
53
    protected $requestCounter = 0;
54
55
    /**
56
     * Agent constructor.
57
     * @param int $max_concurrent max current requests
58
     */
59
    function __construct($max_concurrent = 10)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
60
    {
61
        $this->setMaxConcurrent($max_concurrent);
62
        $this->defaultRequest = new Request();
63
    }
64
65
    function __destruct()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
66
    {
67
        foreach($this->requests as $request) {
68
            curl_multi_remove_handle($this->mh, $request->handle);
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
69
        }
70
        curl_multi_close($this->mh);
71
    }
72
73
    /**
74
     * Magic setter function
75
     * @param string $name attribute to set
76
     * @param mixed $value the new value
77
     * @return void
78
     */
79
    public function __set($name, $value)
80
    {
81
        $c = Request::camelize($name);
82
        $m = "set$c";
83
        if (method_exists($this, $m)) {
84
            $this->$m($value);
85
        } else {
86
            $this->defaultRequest->__set($name, $value);
87
        }
88
    }
89
90
    /**
91
     * Magic getter function
92
     * @param string $name of the attribute to get
93
     * @return mixed the attribute's value
94
     */
95
    public function __get($name)
96
    {
97
        $c = Request::camelize($name);
98
        $m = "get$c";
99
        if (method_exists($this, $m)) {
100
            return $this->$m();
101
        } else {
102
            return $this->defaultRequest->__get($name);
103
        }
104
    }
105
106
    /**
107
     * Set the maximum number of concurrent requests
108
     * @param int $max_requests maximum concurrent requests
109
     */
110
    public function setMaxConcurrent($max_requests)
111
    {
112
        if ($max_requests > 0) {
113
            $this->maxConcurrent = $max_requests;
114
        }
115
    }
116
117
    /**
118
     * Get the currently set value of maxConcurrent
119
     * @return int maximum number of concurrent requests
120
     */
121
    public function getMaxConcurrent()
122
    {
123
        return $this->maxConcurrent;
124
    }
125
126
    /**
127
     * Adds a new request to the queue and returns it
128
     * this request will have its default options set to global options
129
     * @param null $url URL to send the request to
130
     * @return RequestInterface the newly added request object
131
     */
132
    public function newRequest($url = null)
133
    {
134
        $request = clone $this->defaultRequest;
135
        $request->url = $url;
136
        return $this->addRequest($request);
137
    }
138
139
    /**
140
     * Add a request to the request queue
141
     * @param RequestInterface $request the request to add
142
     * @return RequestInterface
143
     */
144
    public function addRequest(RequestInterface $request)
145
    {
146
        $this->requests[] = $request;
147
        return $request;
148
    }
149
150
    /**
151
     * Returns the Request object for a give cUrl handle
152
     * @param resource $handle cUrl handle
153
     * @return RequestInterface Request with handle
154
     */
155
    protected function getRequestByHandle($handle)
156
    {
157
        foreach ($this->requests as $request) {
158
            if ($request->handle === $handle) {
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
159
                return $request;
160
            }
161
        }
162
    }
163
164
    /**
165
     * Execute the request queue
166
     */
167
    public function execute()
168
    {
169
        $this->mh = curl_multi_init();
170
171
        $this->defaultRequest->startTimer();
172
173
        foreach ($this->requests as $key => $request) {
174
            if ($this->requestCounter >= $this->maxConcurrent) {
175
                break;
176
            }
177
            curl_multi_add_handle($this->mh, $request->handle);
0 ignored issues
show
Bug introduced by
Accessing handle on the interface CurlX\RequestInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
178
            $request->startTimer();
179
            $this->requestCounter++;
180
        }
181
182
        // Start the request
183
        do {
184
            $mrc = curl_multi_exec($this->mh, $active);
185
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
186
187
        while ($active && $mrc == CURLM_OK) {
188
            while (curl_multi_exec($this->mh, $active) === CURLM_CALL_MULTI_PERFORM) ;
189
190
            if (curl_multi_select($this->mh) != -1) {
191
                do {
192
                    $mrc = curl_multi_exec($this->mh, $active);
193
                    if ($mrc == CURLM_OK) {
194
                        while ($info = curl_multi_info_read($this->mh)) {
195
                            $this->getRequestByHandle($info['handle'])->callBack($info);
196
                        }
197
                    }
198
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
199
            }
200
        }
201
        $this->defaultRequest->stopTimer();
202
    }
203
}
204