SitePoint Sponsor

User Tag List

Results 1 to 12 of 12
  1. #1
    SitePoint Addict bronze trophy Hall of Famer's Avatar
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    371
    Mentioned
    6 Post(s)
    Tagged
    2 Thread(s)

    Trying to enforce Array type safety, does $array[] resolve to $array->offsetSet()?

    Well in PHP's ArrayObject and SplFixedArray you get this method called offsetSet(). I personally dont think its an elegant way of setting array element, and Id prefer $a[$i] = $val rather than $a->offsetSet($i, $val). So I wonder, is the array syntax $a[] is equivalent to calling offsetSet implicitly? If true, it will be possible to enforce type safety by subclassing Array class and overriding offsetSet method, as shown below:

    PHP Code:
    class StringArray extends SplFixedArray{
       public function 
    offsetSet($index$value){
           if(!
    is_string($str)) throw new IllegalArgumentException("Cannot insert a nonstring element to string array");
           
    parent::($index$value);
       }
    }

    $stringArray = new StringArray(5);
    $stringArray->offsetSet(0"Hello");
    $stringArray->offsetSet(1"World");
    $stringArray->offsetSet(210);  // Error, an exception will be thrown since 10 is not a string object. 
    But is the array syntax gonna work? Anyone ever tried out this idea?
    PHP Code:
    $stringArray = new StringArray;
    $stringArray[0] = "Hello";
    $stringArray[1] = "World";
    $stringArray[2] = 10// Will the script throw an exception, or allow it to pass since its not implicitly calling offsetSet()? 

  2. #2
    SitePoint Evangelist
    Join Date
    Oct 2005
    Location
    Michigan, USA
    Posts
    434
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Anyone ever tried out this idea?
    Have you tried it? I don't understand. Looks like you've written up a basic test case.
    - Robert

  3. #3
    Keeper of the SFL StarLion's Avatar
    Join Date
    Feb 2006
    Location
    Atlanta, GA, USA
    Posts
    3,748
    Mentioned
    73 Post(s)
    Tagged
    0 Thread(s)
    Well the second set doesnt define a length of the StringArray object, so it'll fail when you try and insert anything (because the size defaults to 0). But there should be no error generated by the adding of an integer value in that method, because offsetSet is not called.
    Never grow up. The instant you do, you lose all ability to imagine great things, for fear of reality crashing in.

  4. #4
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,053
    Mentioned
    66 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    So I wonder, is the array syntax $a[] is equivalent to calling offsetSet implicitly?
    Yes, if you are doing an assignment operation. If you are getting the value offsetGet is called.

    If true, it will be possible to enforce type safety by subclassing Array class and overriding offsetSet method
    Which is the whole point of the ArrayObject class. I use it a lot.

    Keep in mind exchangeArray could be used to make an end run around your type restrictions, so you'll need to override it as well. Also, the storage of an ArrayObject is private, so the only way your class can act upon the data internally is through this array access ($this[$i] works with an ArrayObject). So be certain that whatever restrictions you place are internally harmonious.

  5. #5
    @php.net Salathe's Avatar
    Join Date
    Dec 2004
    Location
    Edinburgh
    Posts
    1,397
    Mentioned
    65 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    is the array syntax $a[] is equivalent to calling offsetSet implicitly?
    Yes, using the array-style syntax will call the offset* methods. That is the entire purpose of the ArrayAccess interface that SplFixedArray and ArrayObject both implement.

    Quote Originally Posted by Hall of Famer View Post
    If true, it will be possible to enforce type safety by subclassing Array class and overriding offsetSet method
    You can do whatever you like inside your overriding methods, including throwing exceptions.
    Salathe
    Software Developer and PHP Manual Author.

  6. #6
    SitePoint Addict bronze trophy Hall of Famer's Avatar
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    371
    Mentioned
    6 Post(s)
    Tagged
    2 Thread(s)
    I see, thats excellent. So I can use this notation in the overriden method offsetSet($index, $value) too?

    PHP Code:
    class StringArray extends SplFixedArray{
       public function 
    offsetSet($index$value){
           if(!
    is_string($str)) throw new IllegalArgumentException("Cannot insert a nonstring element to string array");
           
    $this[$index] = $value;
       }

    I wonder what is the difference when it comes to performance factors. Is it faster or slower than calling parent class' offsetSet() method in child method?

  7. #7
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,235
    Mentioned
    154 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    I see, thats excellent. So I can use this notation in the overriden method offsetSet($index, $value) too?

    PHP Code:
    class StringArray extends SplFixedArray{
       public function 
    offsetSet($index$value){
           if(!
    is_string($str)) throw new IllegalArgumentException("Cannot insert a nonstring element to string array");
           
    $this[$index] = $value;
       }

    I wonder what is the difference when it comes to performance factors. Is it faster or slower than calling parent class' offsetSet() method in child method?
    You'd have to setup a benchmark for that, but I imagine you'd only be able to notice the difference when working with nearly a million records. Until that point, it will probably be negligible (at least that's true for C#).

  8. #8
    SitePoint Addict bronze trophy Hall of Famer's Avatar
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    371
    Mentioned
    6 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by cpradio View Post
    You'd have to setup a benchmark for that, but I imagine you'd only be able to notice the difference when working with nearly a million records. Until that point, it will probably be negligible (at least that's true for C#).
    I see, sounds great, I know PHP is about 10-20x slower than C# but still its unlikely to reach near 100k records anyway.

    On a side note, I wonder if this way of typehinting works. Lets say I have both StringArray and NumberArray extending from the parent SplFixedArray class(apparently they are designed to be typesafe), will the below code be valid? Or am I not allowed to change the typehinting mechanism and instead have to validate subtypes inside the method body?

    PHP Code:
    interface ArrayPringer{
        public function print(
    SplFixedArray $array);
    }

    class 
    StringPrinter implements ArrayPrinter{
        public function print(
    StringArray $strings){
            
    // print strings
        
    }
    }

    class 
    NumberPrinter implements ArrayPrinter{
        public function print(
    NumberArray $numbers){
            
    // print numbers
        
    }


  9. #9
    SitePoint Evangelist
    Join Date
    Oct 2005
    Location
    Michigan, USA
    Posts
    434
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    I usually just let people be, but come on! Are you afraid to run code or something? Go try it and find out. (with and without strict error reporting)
    - Robert

  10. #10
    SitePoint Addict bronze trophy Hall of Famer's Avatar
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    371
    Mentioned
    6 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by QMonkey View Post
    I usually just let people be, but come on! Are you afraid to run code or something? Go try it and find out. (with and without strict error reporting)
    Nope, its just that I use a server from a webhost and its quite annoying to have to upload/modify code using FTP. The FTP client cuteftp always disconnects without a reason, its good when you are uploading files but editing files in ftp client is a pain...

    Anyway I find out PHP does not allow derived classes to narrow the scope of typehinting. There was a PHP bug ticket years ago, and unfortunately it has yet to be fixed, or most likely never will be:
    https://bugs.php.net/bug.php?id=37854

    Funny changing typehinting is actually working if the method is not abstract(defined abstract in abstract class or interface), even if you change the typehinting to a completely irrelevant class rather than a subclass. PHP is indeed full of surprises.

  11. #11
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,053
    Mentioned
    66 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    I see, thats excellent. So I can use this notation in the overriden method offsetSet($index, $value) too?

    PHP Code:
    class StringArray extends SplFixedArray{
       public function 
    offsetSet($index$value){
           if(!
    is_string($str)) throw new IllegalArgumentException("Cannot insert a nonstring element to string array");
           
    $this[$index] = $value;
       }

    I wonder what is the difference when it comes to performance factors. Is it faster or slower than calling parent class' offsetSet() method in child method?
    Danger Will Robinson! Danger!!

    The code above creates infinite recursion. Using $this[$key] = $val invokes the class' offsetSet method. So you are invoking it within itself, which is a loop that never resolves. Within the overriding offsetSet function you must call the parent explicitly with parent::offsetSet( $key, $val);

  12. #12
    SitePoint Addict bronze trophy Hall of Famer's Avatar
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    371
    Mentioned
    6 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Michael Morris View Post
    Danger Will Robinson! Danger!!

    The code above creates infinite recursion. Using $this[$key] = $val invokes the class' offsetSet method. So you are invoking it within itself, which is a loop that never resolves. Within the overriding offsetSet function you must call the parent explicitly with parent:ffsetSet( $key, $val);
    Yes it did create an infinite loop, thanks for mentioning. Just fixed it now, looks like I tend to run into this kind of problems. A few weeks ago I had a problem with cloning objects, which also results in infinite loops as in my __clone() method I end up returning $this. XD


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •