1

So I'm working with some external PHP code that I don't have the full source for. I am using reflection to work out callable methods, etc.

They have a class like so:

class SpecialArray implments \ArrayAccess
{
    public function offsetExists($index){}
    public function offsetGet($index){}
    public function offsetSet($index, $value){}
    public function offsetUnset($index){}
}

So logically I can foreach(SpecialArray), that's fine.

However in the code I can somehow do count(SpecialArray) and get the correct count, eg if there are 5 elements in the SpecialArray doing count(SpecialArray) will return 5!

However there isn't a count method in the class, nor does the class implement Countable Calling SpecialArray->count() also fails with Call to undefined method

Does anyone have any ideas how they may be doing this voodoo magic??

Full \ReflectionClass::export()

Class [  class ThirdParty\SpecialArray implements ArrayAccess ] {

  - Constants [0] {
  }

  - Static properties [1] {
    Property [ public static $_metadata ]
  }

  - Static methods [1] {
    Method [  static public method &getMetadata ] {

      - Parameters [0] {
      }
    }
  }

  - Properties [0] {
  }

  - Methods [5] {
    Method [  public method offsetExists ] {

      - Parameters [1] {
        Parameter #0 [  $index ]
      }
    }

    Method [  public method offsetGet ] {

      - Parameters [1] {
        Parameter #0 [  $index ]
      }
    }

    Method [  public method offsetSet ] {

      - Parameters [2] {
        Parameter #0 [  $index ]
        Parameter #1 [  $value ]
      }
    }

    Method [  public method offsetUnset ] {

      - Parameters [1] {
        Parameter #0 [  $index ]
      }
    }

    Method [  public method fetch ] {

      - Parameters [1] {
        Parameter #0 [  $index ]
      }
    }
  }
}
cosmorogers
  • 453
  • 2
  • 14
  • why don't you manually count if you can loop in it ?? – vichu Oct 26 '17 at 14:27
  • Out of curiosity, how do you work with external PHP code you don't have the source for? – M. Eriksson Oct 26 '17 at 14:31
  • 1
    The correct count doesn't happen to be 1, does it? – Don't Panic Oct 26 '17 at 14:33
  • If it is 1 we know the answer ;) – Philipp Palmtag Oct 26 '17 at 14:35
  • @MagnusEriksson with difficulty... – cosmorogers Oct 26 '17 at 14:42
  • @everyone else - calling count(SpecialArray) does return the correct value! EG if there are 5 things in the SpecialArray it will return 5! – cosmorogers Oct 26 '17 at 14:42
  • In this case, can you please provide the full output of `ReflectionClass::export(SpecialArray::class);` as an edit to your question. And maybe also the snippet you've seen `count` getting used in. It might be a custom count from their own namespace that simply does a foreach over the SpecialArray. Thanks. – Gordon Oct 26 '17 at 14:45
  • Added export. I can iterally call `count($thing)`, it isn't namespaced or anything. Can I work out if they have replaced the default php count function with a custom one? – cosmorogers Oct 26 '17 at 14:50
  • By the looks of it this class is loaded from a custom PHP extension, from the third party. Is it possible to replace a core function in a custom extension? – cosmorogers Oct 26 '17 at 14:51
  • @cosmorogers yes, but what makes you think this is a from an extension? – Gordon Oct 26 '17 at 14:53
  • With some more digging I've found a loaded library that has the name of the third party, and I've just found that `ReflectionClass::getFileName` returns `false` (http://php.net/manual/en/reflectionclass.getfilename.php) _If the class is defined in the PHP core or in a PHP extension, FALSE is returned._ – cosmorogers Oct 26 '17 at 14:56
  • To check if there is a function you can use `\ReflectionFunction::export("\\ThirdParty\\count");` Also, what's the name of the extension? – Gordon Oct 26 '17 at 14:58
  • `ConnectPHP`, which is what Oracle call the library/extension/whatever that I'm using. The SpecialArray is also `RightNow\Connect\v1_3\ConnectArray` I doubt anyone has any actual source for that publically. – cosmorogers Oct 26 '17 at 15:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157581/discussion-between-cosmorogers-and-gordon). – cosmorogers Oct 26 '17 at 15:09
  • Can you show a concrete example of the count calls? I found the API docs here http://documentation.custhelp.com/euf/assets/devdocs/november2016/Connect_PHP/Default.htm – Gordon Oct 26 '17 at 15:35
  • Here are some examples from that documentation (didn't know that was public!) http://documentation.custhelp.com/euf/assets/devdocs/november2016/Connect_PHP/Content/Connect%20for%20PHP%20API/RightNow%20Connect%20Object%20Model/Array%20Objects/Array%20Objects.htm So as you can see $org->Addresses is a `RightNow\Connect\v1_3\TypedAddress`, which extends `RightNow\Connect\v1_3\ConnectArray` with no extra functions discovered by reflection – cosmorogers Oct 30 '17 at 10:58

1 Answers1

2

After testing your code, I got the return value of 1. Let me quote the PHP manual of count():

Returns the number of elements in array_or_countable. When the parameter is neither an array nor an object with implemented Countable interface, 1 will be returned. There is one exception, if array_or_countable is NULL, 0 will be returned.

As of PHP 7.2, trying to use count() on something uncountable will give a Warning, such as

Parameter must be an array or an object that implements Countable

Demo https://3v4l.org/G0pR3

Gordon
  • 312,688
  • 75
  • 539
  • 559
Philipp Palmtag
  • 1,310
  • 2
  • 16
  • 18
  • Thanks for the answer, but `count(SpecialArray)` is returning the correct count, eg if there are 7 elements in the SpecialArray (that I can loop over in a foreach, etc), `count(SpecialArray)` returns 7!!!! – cosmorogers Oct 26 '17 at 14:44
  • Do you have more code for us. Like that we wont get far. – Philipp Palmtag Oct 26 '17 at 14:49