Counter

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • zorgi
    Recognized Expert Contributor
    • Mar 2008
    • 431

    Counter

    Hi everyone

    I wrote small counter class. It counts number of daily visits. It remembers all ip addresses per page and counts them only once within any 24 hours per page and it works fine. Here is the code:
    Code:
    class Counter{
    	private static $instance;
    	public static $path = "Counter";
    	private $visits = array();
    	private $ip_reg = array();
    	private $current_date;
    	
    	
    	private function __constructor(){
    		$this -> $current_date = date("m.d.y");			
    	}
    	
    	public static function getFileInstance(){		
    		if(file_exists(self::$path)){
    			self::$instance = (unserialize(file_get_contents(self::$path)));
    		}else{
    			self::$instance = new Counter();
    		}
    		
    		return self::$instance;
    	}
    	
    	private function saveFileInstance(){
    		file_put_contents(self::$path, serialize(self::$instance));	
    	}
    	
    	private function addVisit(){
    		if(isset($this -> visits[$_SERVER['PHP_SELF']])) {
    			$this -> visits[$_SERVER['PHP_SELF']] += 1;
    		}else{
    			$this -> visits[$_SERVER['PHP_SELF']] = 1; 
    		}						
    	}
    	
    	private function register_ip(){
    		if($this -> current_date != date("m.d.y")){
    			$this -> ip_reg = array();
    			$this -> current_date = date("m.d.y");
    		}
    		
    		$ip_adr = $_SERVER['REMOTE_ADDR'];
    		
    		if($this -> ip_reg[$ip_adr][$_SERVER['PHP_SELF']] != 1){
    			$this -> ip_reg[$ip_adr][$_SERVER['PHP_SELF']] = 1;
    			$this -> addVisit();
    			$this -> saveFileInstance();						
    		}	
    		$this -> printCounter();	
    	}
    	
    	private function printCounter(){
    		echo $this -> visits[$_SERVER['PHP_SELF']];
    	}
    	
    	public function run(){
    		$this -> register_ip();
    	}
    }
    My question is what happens if I get 2 visits at the same time. They will get 2 identical instances of the class and obviously one visit will not be recorded. I know its not major issue but am just curious about possible solutions to this problem.

    Thanx
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    Originally posted by zorgi
    My question is what happens if I get 2 visits at the same time. They will get 2 identical instances of the class and obviously one visit will not be recorded.
    I don't think that the 2nd visit gets dropped, because the server would rather queue the http request than dropping it. or in other words: 2 requests = 2 processor threads = running the code seperately. (despite the fact, that "same time" means exactly at the same microsecond)

    note on code:
    I assume you want it to be a singleton, __construct() must be empty (same goes for __clone())! otherwise you can create new instances outside the class.

    the difference between "private function __construct()" and "public function __construct()" is:
    Code:
    class test extends Counter
    {
        function __construct()
        {
            # works not with private declaration
            parent::__construct();
        }
    }
    another way to create the singleton's instance:
    Code:
    self::$instance = new self;
    and some speedup:
    if you're fine with the timestamp (instead of the date), you can read it from the superglobals
    Code:
    $this->$current_date = $_SERVER["REQUEST_TIME"];

    Comment

    • zorgi
      Recognized Expert Contributor
      • Mar 2008
      • 431

      #3
      Originally posted by Dormilich
      I don't think that the 2nd visit gets dropped, because the server would rather queue the http request than dropping it. or in other words: 2 requests = 2 processor threads = running the code seperately.

      note on code:
      I assume you want it to be a singleton, __construct() must be empty (same goes for __clone())! otherwise you can create new instances outside the class.

      the difference between "private function __construct()" and "public function __construct()" is:
      Code:
      class test extends Counter
      {
          function __construct()
          {
              # works not with private declaration
              parent::__construct();
          }
      }
      another way to create the singleton's instance:
      Code:
      self::$instance = new self;
      and some speedup:
      if you're fine with the timestamp (instead of the date), you can read it from the superglobals
      Code:
      $this->$current_date = $_SERVER["REQUEST_TIME"];

      Hi Dormilich
      Thank you for the pointers.

      Yes I wanted to create singleton and am puzzled now. Are you saying that even I declared constructor as private I can still do this: new Counter();
      from outside the class just because constructor is not empty?

      Comment

      • zorgi
        Recognized Expert Contributor
        • Mar 2008
        • 431

        #4
        Originally posted by zorgi
        Hi Dormilich
        Thank you for the pointers.

        Yes I wanted to create singleton and am puzzled now. Are you saying that even I declared constructor as private I can still do this: new Counter();
        from outside the class just because constructor is not empty?
        Oh thought about it bit more and figured it out... Thanks again :)

        Comment

        • Dormilich
          Recognized Expert Expert
          • Aug 2008
          • 8694

          #5
          Originally posted by zorgi
          Yes I wanted to create singleton and am puzzled now. Are you saying that even I declared constructor as private I can still do this: new Counter();
          from outside the class just because constructor is not empty?
          of course, you do it all the time (line #17). that is not a call inside the class (by means of $this-> or self::). magic methods do not work like ordinary methods (compare it with magic constants).

          a compilation of OOP patterns

          Comment

          Working...