Completed
Branch releases/v0.2 (da7ff5)
by Luke
02:45
created

File::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 7
Bugs 0 Features 0
Metric Value
c 7
b 0
f 0
dl 0
loc 17
ccs 10
cts 10
cp 1
rs 9.4285
cc 2
eloc 8
nc 2
nop 4
crap 2
1
<?php
2
/**
3
 * CSVelte: Slender, elegant CSV for PHP.
4
 *
5
 * Inspired by Python's CSV module and Frictionless Data and the W3C's CSV
6
 * standardization efforts, CSVelte was written in an effort to take all the
7
 * suck out of working with CSV.
8
 *
9
 * @version   v0.2
10
 * @copyright Copyright (c) 2016 Luke Visinoni <[email protected]>
11
 * @author    Luke Visinoni <[email protected]>
12
 * @license   https://github.com/deni-zen/csvelte/blob/master/LICENSE The MIT License (MIT)
13
 */
14
namespace CSVelte\IO;
15
16
use CSVelte\Traits\IsReadable;
17
use CSVelte\Traits\IsWritable;
18
use CSVelte\Traits\IsSeekable;
19
20
use \SplFileObject;
21
use CSVelte\Contract\Readable;
22
use CSVelte\Contract\Writable;
23
use CSVelte\Contract\Seekable;
24
25
use CSVelte\Exception\NotYetImplementedException;
26
27
/**
28
 * CSVelte File.
29
 *
30
 * Represents a file for reading/writing. Implements both readable and writable
31
 * interfaces so that it can be passed to either ``CSVelte\Reader`` or
32
 * ``CSVelte\Writer``.
33
 *
34
 * @package    CSVelte
35
 * @subpackage CSVelte\IO
36
 * @copyright  (c) 2016, Luke Visinoni <[email protected]>
37
 * @author     Luke Visinoni <[email protected]>
38
 * @since      v0.2
39
 */
40
class File extends SplFileObject implements Readable, Writable, Seekable
41
{
42
    use IsReadable, IsWritable, IsSeekable;
43
44
    protected $seekable = true;
45
46
    /**
47
     * File Constructor
48
     *
49
     * Exactly the same as native SplFileObject constructor except that first it
50
     * resolves the filename if $use_include_path == true, to avoid weird
51
     * behavior with isReadable and isWritable.
52
     *
53
     * @param string  $filename         The filename to open
54
     * @param string  $open_mode        The fopen mode
55
     * @param boolean $use_include_path Should fopen search the include path
56
     * @param array   $context          An array of context options
57
     */
58 6
    public function __construct($filename, $open_mode = 'r', $use_include_path = false, $context = null)
59
    {
60
        /**
61
         * @note This fixes a possible bug? that causes SplFileObject to return
62
         *     false for isReadable() and isWritable() when $use_include_path
63
         *     is true, even if file exists and is both.
64
         */
65 6
        if ($use_include_path) {
66 1
            $filename = stream_resolve_include_path($filename);
67 1
        }
68 6
        parent::__construct(
69 6
            $filename,
70 6
            $open_mode,
71 6
            $use_include_path,
72
            $context
73 6
        );
74 6
    }
75
76
    /**
77
     * Get the file name.
78
     *
79
     * Return the entire file path and name of this file.
80
     *
81
     * @return string The file path and name
82
     */
83 1
    public function getName()
84
    {
85 1
        return $this->getPath();
86
    }
87
88
    /**
89
     * Read in the specified amount of characters from the file.
90
     *
91
     * Read $length characters from the file and return the resulting string.
92
     *
93
     * @param integer $length Amount of characters to read from file
94
     * @return string The specified amount of characters read from file
95
     */
96 3
    public function read($length)
97
    {
98 3
        $this->assertIsReadable();
99 3
        return $this->fread($length);
1 ignored issue
show
Bug introduced by
The method fread() does not seem to exist on object<CSVelte\IO\File>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
100
    }
101
102
    /**
103
     * Read the entire contents of file
104
     *
105
     * @param void
106
     * @return string The entire file contents
107
     * @access public
108
     */
109
    public function getContents()
110
    {
111
        return $this->read($this->getSize());
112
    }
113
114
    /**
115
     * Write data to the output
116
     *
117
     * @param string The data to write
118
     * @return int The number of bytes written
119
     * @access public
120
     */
121 4
    public function write($data)
122
    {
123 4
        $this->assertIsWritable();
124 4
        return $this->fwrite($data);
125
    }
126
127
    /**
128
     * Accessor for seekability.
129
     *
130
     * Returns true if possible to seek to a certain position within this file.
131
     *
132
     * @return boolean True if stream is seekable
133
     */
134 1
    public function isSeekable()
135
    {
136 1
        return $this->seekable;
137
    }
138
139
    /**
140
     * Seek to a position within an input
141
     *
142
     * @param integer Offset to seek to
143
     * @param integer Position from whence the offset should be applied
144
     * @return boolean True if seek was successful
145
     * @access public
146
     */
147 2
    public function seek($pos, $whence = SEEK_SET)
148
    {
149 2
        $this->assertIsSeekable();
150 2
        return $this->fseek($pos, $whence);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->fseek($pos, $whence); (integer) is incompatible with the return type declared by the interface CSVelte\Contract\Seekable::seek of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
151
    }
152
}
153