2
\$\begingroup\$

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
\$\endgroup\$
  • 1
    \$\begingroup\$ the :: operator, or T_PAAMAYIM_NEKUDOTAYIM if you like that, is an operator for static methods and class constants, to call a method use $this->method(). \$\endgroup\$ – Wouter J Mar 13 '13 at 15:09
  • \$\begingroup\$ @WouterJ Ah yes, I remember learning this at one point. Thank you, I will correct. \$\endgroup\$ – jnthnjns Mar 13 '13 at 15:17
2
\$\begingroup\$
  1. Never ever use var. That's a deprecated form of public;
  2. Avoid using public on your properties, you want to have controll about the value of every property in your class;
  3. If you use protected or private 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";

  4. The :: operator, or T_PAAMAYIM_NEKUDOTAYIM, should only be used by accessing class constants and static vars/methods;
  5. Avoid using static vars/methods;
  6. 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).
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.