Completed
Push — master ( a4fa7b...83f79a )
by Vasily
05:57
created

File::read()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 27
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 27
rs 6.7272
cc 7
eloc 21
nc 7
nop 4
1
<?php
2
namespace PHPDaemon\FS;
3
4
use PHPDaemon\Network\IOStream;
5
use PHPDaemon\Structures\StackCallbacks;
6
use PHPDaemon\Core\CallbackWrapper;
7
8
/**
9
 * File
10
 * @package PHPDaemon\FS
11
 * @author  Vasily Zorin <[email protected]>
12
 */
13
class File {
14
	use \PHPDaemon\Traits\ClassWatchdog;
15
	use \PHPDaemon\Traits\StaticObjectWatchdog;
16
17
	/**
18
	 * @var integer Priority
19
	 */
20
	public $priority = 10;
21
22
	/**
23
	 * @var integer Chunk size
24
	 */
25
	public $chunkSize = 4096;
26
27
	/**
28
	 * @var string $stat hash Stat
29
	 */
30
	protected $stat;
31
32
	/**
33
	 * @var array Cache of statvfs()
34
	 */
35
	protected $statvfs;
36
37
	/**
38
	 * @var integer Current offset
39
	 */
40
	public $offset = 0;
41
42
	/**
43
	 * @var string Cache key
44
	 */
45
	public $fdCacheKey;
46
47
	/**
48
	 * @var boolean Append?
49
	 */
50
	public $append;
51
52
	/**
53
	 * @var string Path
54
	 */
55
	public $path;
56
57
	/**
58
	 * @var boolean Writing?
59
	 */
60
	public $writing = false;
61
62
	/**
63
	 * @var boolean Closed?
64
	 */
65
	public $closed = false;
66
67
	/**
68
	 * @var object File descriptor
69
	 */
70
	protected $fd;
71
72
	/**
73
	 * @var PHPDaemon\Structures\StackCallbacks Stack of callbacks called when writing is done
74
	 */
75
	protected $onWriteOnce;
76
77
	/**
78
	 * File constructor
79
	 * @param resource $fd   Descriptor
80
	 * @param string   $path Path
81
	 */
82
	public function __construct($fd, $path) {
83
		$this->fd          = $fd;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fd of type resource is incompatible with the declared type object of property $fd.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
84
		$this->path        = $path;
85
		$this->onWriteOnce = new StackCallbacks;
0 ignored issues
show
Documentation Bug introduced by
It seems like new \PHPDaemon\Structures\StackCallbacks() of type object<PHPDaemon\Structures\StackCallbacks> is incompatible with the declared type object<PHPDaemon\FS\PHPD...uctures\StackCallbacks> of property $onWriteOnce.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
86
	}
87
88
	/**
89
	 * Get file descriptor
90
	 * @return resource File descriptor
0 ignored issues
show
Documentation introduced by
Should the return type not be object?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
91
	 */
92
	public function getFd() {
93
		return $this->fd;
94
	}
95
96
	/**
97
	 * Converts string of flags to integer or standard text representation
98
	 * @param  string  $mode Mode
99
	 * @param  boolean $text Text?
100
	 * @return mixed
101
	 */
102
	public static function convertFlags($mode, $text = false) {
103
		$plus = strpos($mode, '+') !== false;
104
		$sync = strpos($mode, 's') !== false;
105
		$type = strtr($mode, ['b' => '', '+' => '', 's' => '', '!' => '']);
106
		if ($text) {
107
			return $type;
108
		}
109
		$types = [
110
			'r' => $plus ? EIO_O_RDWR : EIO_O_RDONLY,
111
			'w' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT | EIO_O_TRUNC,
112
			'a' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT | EIO_O_APPEND,
113
			'x' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_EXCL | EIO_O_CREAT,
114
			'c' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT,
115
		];
116
		$m     = $types[$type];
117
		if ($sync) {
118
			$m |= EIO_O_FSYNC;
119
		}
120
		return $m;
121
	}
122
123
	/**
124
	 * Truncates this file
125
	 * @param  integer  $offset Offset. Default is 0
126
	 * @param  callable $cb     Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
127
	 * @param  integer  $pri    Priority
128
	 * @return resource|boolean
129
	 */
130 View Code Duplication
	public function truncate($offset = 0, $cb = null, $pri = EIO_PRI_DEFAULT) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 131 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
132
		if (!$this->fd || $this->fd === -1) {
133
			if ($cb) {
134
				$cb($this, false);
135
			}
136
			return false;
137
		}
138
		if (!FileSystem::$supported) {
139
			$fp = fopen($this->path, 'r+');
140
			$r  = $fp && ftruncate($fp, $offset);
141
			if ($cb) {
142
				$cb($this, $r);
143
			}
144
			return $r;
145
		}
146
		return eio_ftruncate($this->fd, $offset, $pri, $cb, $this);
147
	}
148
149
	/**
150
	 * Stat()
151
	 * @param  callable $cb  Callback
152
	 * @param  integer  $pri Priority
153
	 * @return resource|boolean
154
	 */
155
	public function stat($cb, $pri = EIO_PRI_DEFAULT) {
156
		$cb = CallbackWrapper::forceWrap($cb);
157
		if (!$this->fd || $this->fd === -1) {
158
			if ($cb) {
159
				$cb($this, false);
160
			}
161
			return false;
162
		}
163 View Code Duplication
		if (!FileSystem::$supported) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
			$cb($this, FileSystem::statPrepare(fstat($this->fd)));
165
			return false;
166
		}
167
		if ($this->stat) {
168
			$cb($this, $this->stat);
169
			return true;
170
		}
171
		return eio_fstat($this->fd, $pri, function ($file, $stat) use ($cb) {
172
			$stat       = FileSystem::statPrepare($stat);
173
			$file->stat = $stat;
174
			$cb($file, $stat);
175
		}, $this);
176
	}
177
178
	/**
179
	 * Stat() non-cached
180
	 * @param  callable $cb  Callback
181
	 * @param  integer  $pri Priority
182
	 * @return resource|boolean
183
	 */
184
	public function statRefresh($cb, $pri = EIO_PRI_DEFAULT) {
185
		$cb = CallbackWrapper::forceWrap($cb);
186
		if (!$this->fd || $this->fd === -1) {
187
			if ($cb) {
188
				$cb($this, false);
189
			}
190
			return false;
191
		}
192 View Code Duplication
		if (!FileSystem::$supported) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
			$cb($this, FileSystem::statPrepare(fstat($this->fd)));
194
			return true;
195
		}
196
		return eio_fstat($this->fd, $pri, function ($file, $stat) use ($cb) {
197
			$stat       = FileSystem::statPrepare($stat);
198
			$file->stat = $stat;
199
			$cb($file, $stat);
200
		}, $this);
201
	}
202
203
	/**
204
	 * Statvfs()
205
	 * @param  callable $cb  Callback
206
	 * @param  integer  $pri Priority
207
	 * @return resource|boolean
208
	 */
209
	public function statvfs($cb, $pri = EIO_PRI_DEFAULT) {
210
		$cb = CallbackWrapper::forceWrap($cb);
211
		if (!$this->fd) {
212
			if ($cb) {
213
				$cb($this, false);
214
			}
215
			return false;
216
		}
217
		if (!FileSystem::$supported) {
218
			if ($cb) {
219
				$cb($this, false);
220
			}
221
			return false;
222
		}
223
		if ($this->statvfs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->statvfs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
224
			$cb($this, $this->statvfs);
225
			return true;
226
		}
227
		return eio_fstatvfs($this->fd, $pri, function ($file, $stat) use ($cb) {
228
			$file->statvfs = $stat;
229
			$cb($file, $stat);
230
		}, $this);
231
	}
232
233
	/**
234
	 * Sync()
235
	 * @param  callable $cb  Callback
236
	 * @param  integer  $pri Priority
237
	 * @return resource|false
238
	 */
239 View Code Duplication
	public function sync($cb, $pri = EIO_PRI_DEFAULT) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
		$cb = CallbackWrapper::forceWrap($cb);
241
		if (!$this->fd) {
242
			if ($cb) {
243
				$cb($this, false);
244
			}
245
			return false;
246
		}
247
		if (!FileSystem::$supported) {
248
			$cb($this, true);
249
			return false;
250
		}
251
		return eio_fsync($this->fd, $pri, $cb, $this);
252
	}
253
254
	/**
255
	 * Datasync()
256
	 * @param  callable $cb  Callback
257
	 * @param  integer  $pri Priority
258
	 * @return resource|false
259
	 */
260 View Code Duplication
	public function datasync($cb, $pri = EIO_PRI_DEFAULT) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
261
		$cb = CallbackWrapper::forceWrap($cb);
262
		if (!$this->fd) {
263
			if ($cb) {
264
				$cb($this, false);
265
			}
266
			return false;
267
		}
268
		if (!FileSystem::$supported) {
269
			$cb($this, true);
270
			return false;
271
		}
272
		return eio_fdatasync($this->fd, $pri, $cb, $this);
273
	}
274
275
	/**
276
	 * Writes data to file
277
	 * @param  string   $data   Data
278
	 * @param  callable $cb     Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
279
	 * @param  integer  $offset Offset
0 ignored issues
show
Documentation introduced by
Should the type for parameter $offset not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
280
	 * @param  integer  $pri    Priority
281
	 * @return resource|false
282
	 */
283
	public function write($data, $cb = null, $offset = null, $pri = EIO_PRI_DEFAULT) {
284
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 284 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
285
		if (!$this->fd) {
286
			if ($cb) {
287
				$cb($this, false);
288
			}
289
			return false;
290
		}
291
		if ($data === '') {
292
			if ($cb) {
293
				$cb($this, 0);
294
			}
295
			return false;
296
		}
297
		if (!FileSystem::$supported) {
298
			if ($offset !== null) {
299
				fseek($data, $offset);
300
			}
301
			$r = fwrite($this->fd, $data);
302
			if ($cb) {
303
				$cb($this, $r);
304
			}
305
			return false;
306
		}
307
		if ($cb !== null) {
308
			$this->onWriteOnce->push($cb);
309
		}
310
		$l = strlen($data);
311
		if ($offset === null) {
312
			$offset = $this->offset;
313
			$this->offset += $l;
314
		}
315
		$this->writing = true;
316
		$res           = eio_write($this->fd, $data, $l, $offset, $pri, function ($file, $result) {
317
			$this->writing = false;
318
			$this->onWriteOnce->executeAll($file, $result);
319
		}, $this);
320
		return $res;
321
	}
322
323
	/**
324
	 * Changes ownership of this file
325
	 * @param  integer  $uid User ID
326
	 * @param  integer  $gid Group ID
327
	 * @param  callable $cb  Callback
328
	 * @param  integer  $pri Priority
329
	 * @return resource|false
330
	 */
331 View Code Duplication
	public function chown($uid, $gid = -1, $cb, $pri = EIO_PRI_DEFAULT) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
332
		$cb = CallbackWrapper::forceWrap($cb);
333
		if (!$this->fd) {
334
			if ($cb) {
335
				$cb($this, false);
336
			}
337
			return false;
338
		}
339
		if (!FileSystem::$supported) {
340
			$r = chown($this->path, $uid);
341
			if ($gid !== -1) {
342
				$r = $r && chgrp($this->path, $gid);
343
			}
344
			if ($cb) {
345
				$cb($this, $r);
346
			}
347
			return false;
348
		}
349
		return eio_fchown($this->fd, $uid, $gid, $pri, $cb, $this);
350
	}
351
352
	/**
353
	 * touch()
354
	 * @param  integer  $mtime Last modification time
355
	 * @param  integer  $atime Last access time
0 ignored issues
show
Documentation introduced by
Should the type for parameter $atime not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
356
	 * @param  callable $cb    Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
357
	 * @param  integer  $pri   Priority
358
	 * @return resource|false
359
	 */
360
	public function touch($mtime, $atime = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
361
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 361 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
362
		if (!$this->fd) {
363
			if ($cb) {
364
				$cb($this, false);
365
			}
366
			return false;
367
		}
368
		if (!FileSystem::$supported) {
369
			$r = touch($this->path, $mtime, $atime);
370
			if ($cb) {
371
				$cb($this, $r);
372
			}
373
			return false;
374
		}
375
		return eio_futime($this->fd, $atime, $mtime, $pri, $cb, $this);
376
	}
377
378
	/**
379
	 * Clears cache of stat() and statvfs()
380
	 * @return void
381
	 */
382
	public function clearStatCache() {
383
		$this->stat    = null;
384
		$this->statvfs = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $statvfs.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
385
	}
386
387
	/**
388
	 * Reads data from file
389
	 * @param  integer  $length Length
390
	 * @param  integer  $offset Offset
0 ignored issues
show
Documentation introduced by
Should the type for parameter $offset not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
391
	 * @param  callable $cb     Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
392
	 * @param  integer  $pri    Priority
393
	 * @return boolean
0 ignored issues
show
Documentation introduced by
Should the return type not be string|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
394
	 */
395
	public function read($length, $offset = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
396
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 396 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
397
		if (!$this->fd) {
398
			if ($cb) {
399
				$cb($this, false);
400
			}
401
			return false;
402
		}
403
		if (!FileSystem::$supported) {
404
			if ($offset !== null) {
405
				fseek($this->fd, $length);
406
			}
407
			$data = fread($this->fd, $length);
408
			$cb === null || $cb($this, $data);
409
			return $data;
410
		}
411
		$this->offset += $length;
412
		eio_read(
413
			$this->fd,
414
			$length,
415
			$offset !== null ? $offset : $this->offset,
416
			$pri,
417
			$cb,
418
			$this
419
		);
420
		return true;
421
	}
422
423
	/**
424
	 * sendfile()
425
	 * @param  mixed    $outfd   File descriptor
426
	 * @param  callable $cb      Callback
427
	 * @param  callable $startCb Start callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $startCb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
428
	 * @param  integer  $offset  Offset
429
	 * @param  integer  $length  Length
0 ignored issues
show
Documentation introduced by
Should the type for parameter $length not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
430
	 * @param  integer  $pri     Priority
431
	 * @return boolean           Success
432
	 */
433
	public function sendfile($outfd, $cb, $startCb = null, $offset = 0, $length = null, $pri = EIO_PRI_DEFAULT) {
434
		$cb = CallbackWrapper::forceWrap($cb);
435
		if (!$this->fd) {
436
			if ($cb) {
437
				$cb($this, false);
438
			}
439
			return false;
440
		}
441
		if (!FileSystem::$supported) {
442
			if ($cb) {
443
				$cb($this, false);
444
			}
445
			return false;
446
		}
447
		static $chunkSize = 1024;
448
		$ret     = true;
449
		$handler = function ($file, $sent = -1) use (&$ret, $outfd, $cb, &$handler, &$offset, &$length, $pri, $chunkSize) {
450
			if ($outfd instanceof IOStream) {
451
				if ($outfd->isFreed()) {
452
					$cb($file, false);
453
					return;
454
				}
455
				$ofd = $outfd->getFd();
456
			}
457
			else {
458
				$ofd = $outfd;
459
			}
460
			if (!$ret) {
461
				$cb($file, false);
462
				return;
463
			}
464
			if ($sent === -1) {
465
				$sent = 0;
466
			}
467
			$offset += $sent;
468
			$length -= $sent;
469
			if ($length <= 0) {
470
				$cb($file, true);
471
				return;
472
			}
473
			if (!$ofd) {
474
				$cb($file, false);
475
				return;
476
			}
477
			$c   = min($chunkSize, $length);
478
			$ret = eio_sendfile($ofd, $file->fd, $offset, $c, $pri, $handler, $file);
479
		};
480
		if ($length !== null) {
481
			if ($startCb !== null) {
482
				if (!$startCb($this, $length, $handler)) {
483
					$handler($this);
484
				}
485
			}
486
			else {
487
				$handler($this);
488
			}
489
			return true;
490
		}
491
		$this->statRefresh(function ($file, $stat) use ($startCb, $handler, &$length) {
492
			$length = $stat['size'];
493
			if ($startCb !== null) {
494
				if (!$startCb($file, $length, $handler)) {
495
					$handler($file);
496
				}
497
			}
498
			else {
499
				$handler($file);
500
			}
501
		}, $pri);
502
		return true;
503
	}
504
505
	/**
506
	 * readahead()
507
	 * @param  integer  $length Length
508
	 * @param  integer  $offset Offset
0 ignored issues
show
Documentation introduced by
Should the type for parameter $offset not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
509
	 * @param  callable $cb     Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
510
	 * @param  integer  $pri    Priority
511
	 * @return resource|false
512
	 */
513
	public function readahead($length, $offset = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
514
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 514 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
515
		if (!$this->fd) {
516
			if ($cb) {
517
				$cb($this, false);
518
			}
519
			return false;
520
		}
521
		if (!FileSystem::$supported) {
522
			if ($cb) {
523
				$cb($this, false);
524
			}
525
			return false;
526
		}
527
		$this->offset += $length;
528
		return eio_readahead(
529
			$this->fd,
530
			$length,
531
			$offset !== null ? $offset : $this->offset,
532
			$pri,
533
			$cb,
534
			$this
535
		);
536
	}
537
538
	/**
539
	 * Generates closure-callback for readAll
540
	 * @param  callable $cb
541
	 * @param  integer  $size
542
	 * @param  integer  &$offset
543
	 * @param  integer  &$pri
544
	 * @param  string   &$buf
545
	 * @return callable
546
	 */
547 View Code Duplication
	protected function readAllGenHandler($cb, $size, &$offset, &$pri, &$buf) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
548
		return function ($file, $data) use ($cb, $size, &$offset, &$pri, &$buf) {
549
			$buf .= $data;
550
			$offset += strlen($data);
551
			$len = min($file->chunkSize, $size - $offset);
552
			if ($offset >= $size) {
553
				if ($cb) {
554
					$cb($file, $buf);
555
				}
556
				return;
557
			}
558
			eio_read($file->fd, $len, $offset, $pri, $this->readAllGenHandler($cb, $size, $offset, $pri, $buf), $this);
559
		};
560
	}
561
562
	/**
563
	 * Reads whole file
564
	 * @param  callable $cb  Callback
565
	 * @param  integer  $pri Priority
566
	 * @return boolean       Success
567
	 */
568
	public function readAll($cb, $pri = EIO_PRI_DEFAULT) {
569
		$cb = CallbackWrapper::forceWrap($cb);
570
		if (!$this->fd) {
571
			if ($cb) {
572
				$cb($this, false);
573
			}
574
			return false;
575
		}
576 View Code Duplication
		$this->statRefresh(function ($file, $stat) use ($cb, $pri) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
577
			if (!$stat) {
578
				if ($cb) {
579
					$cb($file, false);
580
				}
581
				return;
582
			}
583
			$offset = 0;
584
			$buf    = '';
585
			$size   = $stat['size'];
586
			eio_read($file->fd, min($file->chunkSize, $size), 0, $pri, $this->readAllGenHandler($cb, $size, $offset, $pri, $buf), $file);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 569 can be null; however, PHPDaemon\FS\File::readAllGenHandler() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 128 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
587
		}, $pri);
588
		return true;
589
	}
590
591
	/**
592
	 * Generates closure-callback for readAllChunked
593
	 * @param  callable $cb
594
	 * @param  callable $chunkcb
595
	 * @param  integer  $size
596
	 * @param  integer  $offset
597
	 * @param  integer  $pri
598
	 * @return callable
599
	 */
600 View Code Duplication
	protected function readAllChunkedGenHandler($cb, $chunkcb, $size, &$offset, $pri) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
601
		return function ($file, $data) use ($cb, $chunkcb, $size, &$offset, $pri) {
602
			$chunkcb($file, $data);
603
			$offset += strlen($data);
604
			$len = min($file->chunkSize, $size - $offset);
605
			if ($offset >= $size) {
606
				$cb($file, true);
607
				return;
608
			}
609
			eio_read($file->fd, $len, $offset, $pri, $this->readAllChunkedGenHandler($cb, $chunkcb, $size, $offset, $pri), $file);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
610
		};
611
	}
612
613
	/**
614
	 * Reads file chunk-by-chunk
615
	 * @param  callable $cb      Callback
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
616
	 * @param  callable $chunkcb Callback of chunk
0 ignored issues
show
Documentation introduced by
Should the type for parameter $chunkcb not be callable|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
617
	 * @param  integer  $pri     Priority
618
	 * @return resource|false
0 ignored issues
show
Documentation introduced by
Should the return type not be resource|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
619
	 */
620
	public function readAllChunked($cb = null, $chunkcb = null, $pri = EIO_PRI_DEFAULT) {
621
		$cb = CallbackWrapper::forceWrap($cb);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 621 can also be of type null; however, PHPDaemon\Core\CallbackWrapper::forceWrap() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
622
		if (!$this->fd) {
623
			if ($cb) {
624
				$cb($this, false);
625
			}
626
			return false;
627
		}
628 View Code Duplication
		return $this->statRefresh(function ($file, $stat) use ($cb, $chunkcb, $pri) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
629
			if (!$stat) {
630
				$cb($file, false);
631
				return;
632
			}
633
			$offset = 0;
634
			$size   = $stat['size'];
635
			eio_read($file->fd, min($file->chunkSize, $size), $offset, $pri, $this->readAllChunkedGenHandler($cb, $chunkcb, $size, $offset, $pri), $file);
0 ignored issues
show
Bug introduced by
It seems like $cb defined by \PHPDaemon\Core\CallbackWrapper::forceWrap($cb) on line 621 can be null; however, PHPDaemon\FS\File::readAllChunkedGenHandler() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
Bug introduced by
It seems like $chunkcb defined by parameter $chunkcb on line 620 can also be of type null; however, PHPDaemon\FS\File::readAllChunkedGenHandler() does only seem to accept callable, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 145 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
636
		}, $pri);
637
	}
638
639
	/**
640
	 * toString handler
641
	 * @return string
642
	 */
643
	public function __toString() {
644
		return $this->path;
645
	}
646
647
	/**
648
	 * Set chunk size
649
	 * @param  integer $n Chunk size
650
	 * @return void
651
	 */
652
	public function setChunkSize($n) {
653
		$this->chunkSize = $n;
654
	}
655
656
	/**
657
	 * Move pointer to arbitrary position
658
	 * @param  integer  $offset Offset
659
	 * @param  callable $cb     Callback
660
	 * @param  integer  $pri    Priority
661
	 * @return resource|false
662
	 */
663
	public function seek($offset, $cb, $pri = EIO_PRI_DEFAULT) {
664
		$cb = CallbackWrapper::forceWrap($cb);
665
		if (!\EIO::$supported) {
666
			fseek($this->fd, $offset);
667
			return false;
668
		}
669
		return eio_seek($this->fd, $offset, $pri, $cb, $this);
670
	}
671
672
	/**
673
	 * Get current pointer position
674
	 * @return integer
675
	 */
676
	public function tell() {
677
		if (\EIO::$supported) {
678
			return $this->offset;
679
		}
680
		return ftell($this->fd);
681
	}
682
683
	/**
684
	 * Close the file
685
	 * @return resource|false
686
	 */
687
	public function close() {
688
		if ($this->closed) {
689
			return false;
690
		}
691
		$this->closed = true;
692
		if ($this->fdCacheKey !== null) {
693
			FileSystem::$fdCache->invalidate($this->fdCacheKey);
694
		}
695
		if ($this->fd === null) {
696
			return false;
697
		}
698
699
		if (!FileSystem::$supported) {
700
			fclose($this->fd);
701
			return false;
702
		}
703
		$r        = eio_close($this->fd, EIO_PRI_MAX);
704
		$this->fd = null;
705
		return $r;
706
	}
707
708
	/**
709
	 * Destructor
710
	 */
711
	public function __destruct() {
712
		$this->close();
713
	}
714
}
715