Problem
I have done a lot of research on OOP and I keep seeming to read different opinions on several items, especially the scope resolution operator (::
) and handling class containing private functions.
When calling a private function from within the class
it seems that a majority of programmers recommend self::method()
, is this accurate? I have also seen and tested Class::method()
.
Also, I am looking for more information, or recommendations on appropriate ways to instantiate class variables, whether it be protected
, private
, var
, etc…
Take this Timer
class I wrote for example:
class Timer {
protected $_start, $_pause, $_stop, $_elapsed;
protected $_laps = array();
protected $_count = 1;
protected $_lapTotalTime = 0;
public function __construct($start = '') {
$start = strtolower($start);
($start === 'start') ? self::start() : NULL;
}
public function start( ) {
$this->_start = Timer::getMicroTime();
}
public function stop( ) {
$this->_stop = Timer::getMicroTime();
}
public function pause( ) {
$this->_pause = Timer::getMicroTime();
$this->_elapsed += ($this->_pause - $this->_start);
}
public function resume( ) {
$this->_start = Timer::getMicroTime();
}
// Used to build an array of times for multiple timers
public function lap($key = '') {
($key === '') ? $key = 'Lap' : $key = $key;
if (isset($this->_start)) {
self::stop();
$this->_lapTotalTime += ($this->_stop - $this->_start);
$this->_laps[$key.' '.$this->_count] = self::getLapTime();
self::start();
$this->_count++;
}
}
public function getTime() {
if (!isset($this->_stop)) {
$this->_stop = Timer::getMicroTime();
}
if (!empty($this->_laps)) {
$this->_laps['Total'] = self::timeToString($this->_lapTotalTime);
return $this->_laps;
}
return self::timeToString();
}
// PRIVATE CLASS FUNCTIONS
private function getLapTime() {
return self::timeToString();
}
private function getMicroTime( ) {
list($usec, $sec) = explode(' ', microtime());
return ((float) $usec + (float) $sec);
}
private function timeToString($seconds = '') {
if ($seconds === '') {
$seconds = ($this->_stop - $this->_start) + $this->_elapsed;
}
$seconds = Timer::roundMicroTime($seconds);
$hours = floor($seconds / (60 * 60));
$divisor_for_minutes = $seconds % (60 * 60);
$minutes = floor($divisor_for_minutes / 60);
return $hours . "h:" . $minutes . "m:" . $seconds . "s";
}
private function roundMicroTime($microTime) {
return round($microTime, 4, PHP_ROUND_HALF_UP);
}
}
All of my instantiated variables are declared as protected
. My reasoning, if I am understanding correctly is because although this Class doesn’t extend
another class, the other class may extend
Timer
. Am I on the right track?
Example of Timer
use with laps:
$t = new Timer('start');
usleep(3215789);
// Declare a key for the lap array
$t->lap('Sleep');
usleep(4445666);
// No key declaration
$t->lap();
usleep(1000000);
echo "<pre>";
if (is_array($t->getTime())) {
print_r($t->getTime());
} else {
echo $t->getTime();
}
echo "</pre>";
Output:
Array ( [Sleep 1] => 0h:0m:3.2154s [Lap 2] => 0h:0m:4.4462s [Total] => 0h:0m:7.6616s )
Without laps:
$t = new Timer('start');
usleep(3215789);
usleep(1000000);
echo "<pre>";
if (is_array($t->getTime())) {
print_r($t->getTime());
} else {
echo $t->getTime();
}
echo "</pre>";
Output:
0h:0m:4.2158s
Solution
- Never ever use
var
. That’s a deprecated form ofpublic
; - Avoid using
public
on your properties, you want to have controll about the value of every property in your class; -
If you use
protected
orprivate
doesn’t make much sense. Protected means it can’t be accessed from the outer scope, but it can be accessed from another class which extends this class. Private means it can only be accessed from the class where it is defined.I like to have getters/setters for every property and never use
$this->property
directly inside my class, some other don’t like that. See also this article by Fabien Potencier: “Pragmatism over Theory: Protected vs Private”; - The
::
operator, orT_PAAMAYIM_NEKUDOTAYIM
, should only be used by accessing class constants and static vars/methods; - Avoid using static vars/methods;
- Use
$this->method()
or$this->property
to access properties from the inside of a class. It works just like you use it outside the class, except that you use the$this
variable (which contains a reference to the current instance of the class).