Type safe working with PHP arrays

Hello everyone, I’ll tell you about my own bike for convenient work with arrays in PHP.



Type hinting



Type hinting appeared in PHP7, which allowed the IDE to perform better static analysis of the code, the quality of our code improved (or correctly says " it got better "?).



Of course, earlier it was possible for the IDE to write a hint in the comments to the code, but now the types have become part of the code and now it has become possible to refactor and not be afraid that you will forget something somewhere (refactor of course in the sense of renaming classes and interfaces).



Besides the fact that it became possible to specify the output type, it became possible to specify the type of the input argument.



But besides the nice features, type hinting also imposes responsibilities, that is, the types of variables really should be as indicated in the method signature.



If you do not check types, you can get errors in methods and constructors (errors in designers are especially encouraging).



Writing checks manually is tedious, I decided to automate this business, but not through verification, but through casting to the desired type.



In my work, quite often I have to write from scratch, usually it’s either prototypes, or parsers, or ETLs for a new data source, in fact also a parser.



Of course you work with arrays (for example, when you read from * .csv), you can work with the database through ORM, but for my tasks it is too cumbersome, it is convenient for me to work with the database through PDO, which gives you data again in arrays. “Favorite” Bitrix does not know how to return data other than in an array.



No matter how you have to retrieve data from arrays. So I wrote a wrapper for working with arrays.



In order not to copy-paste the code from project to project, I designed the package for Composer :



composer require sbwerewolf/language-specific
      
      





Valuehandler



My first requirement was to always know what type I would receive. Before this, of course, we would still have to get the value, probably by the index, so we came to the conclusion that we need the get () method.



And now we need methods for type casting, there are not many types in PHP, we have the following methods:



  1. int ()
  2. str ()
  3. bool ()
  4. double ()


Arrays sometimes come across, so let it be for arrays:





Sometimes you just need to get the element as it is:





Sometimes there may not be an element with a given index, and then you need to use the default value:





Arrayhandler



The next requirement was to be able to simplify the array from one value to exactly this value.



I will show you an example from the documentation:



 $connection = new PDO ($dsn,$login,$password); $command = $connection->prepare('select name from employee where salary > 10000'); $command->execute(); $data = $command->fetchAll(PDO::FETCH_ASSOC); /* $data = array ( 0 => array ( 'name' => 'Mike', ), 1 => array ( 'name' => 'Tom', ), 2 => array ( 'name' => 'Jerry', ), 3 => array ( 'name' => 'Mary', ) ); */ $names = new ArrayHandler($data); $result = $names->simplify(); echo var_export($result,true); /* LanguageSpecific\ArrayHandler::__set_state(array( '_data' => array ( 0 => 'Mike', 1 => 'Tom', 2 => 'Jerry', 3 => 'Mary', ), )) */
      
      





You can of course run through the array that will be returned from the request and do this assignment:



 $response[] = $element[0];
      
      





, but I don’t like it so much, let it happen automatically, so the simplify () method appeared.



Well, since we have a wrapper over the array, we will add a method to check for the presence of the index - has (), if you want to go over the elements of the array, the next () method will help.



This could have been stopped because the automation level reached a comfortable level, but sometimes I have to work with a nested array of a nested array, and it is more convenient for me to immediately get an ArrayHandler for the target array, so I added the pull () method, which returns ArrayHandler for the nested array .



It looks like this:



 $address = new ArrayHandler($item)->pull('metaDataProperty')->pull('GeocoderMetaData')->pull('Address')->asIs();
      
      





You can of course write like this:



 $address = $item['GeoObject']['metaDataProperty']['GeocoderMetaData']['Address'];
      
      





, but in my eyes ripples on the number of square brackets, it is more convenient for me through pull ().



General reasoning



When the code is connected from Composer it is very convenient, except that you get rid of the need to copy-paste, you get your library with one command and it is always at hand.



Before making my package, I looked at the analogs and didn’t find anything like it, there are several projects that simply wrap on an array, and in these projects they simply wrap many methods for working with arrays, and there is no type safety anywhere.



Apparently, writing (int) or (bool) in front of the variable name is simple and convenient for everyone and no one sees any reason to bother with a separate repository for this thing.



The library features are slightly wider than those described in the article and more information can be obtained in the documentation (README.md) .



PHP5 is not uncommon yet, therefore the library has a separate version for PHP5, differs from the version for PHP7 by the name of several methods, and of course all type hinting is only in comments.

There is a library version for PHP7.2, it differs only in that the type of the return value appears in the signature of the object () method - object.



The code is completely covered by tests, but in principle there’s nothing to break :)



Use for health!



Another use case



 foreach ($featureMember as $item) { $pointInfo = extract($item); $info = new ArrayHandler($pointInfo); $address = $info->get('formatted')->default('')->str(); $longitude = $info->get('longitude')->default(61.402554)->double(); $latitude = $info->get('latitude')->default(55.159897)->double(); $undefined = !$info->get('formatted')->has(); $properties = ['longitude' => $longitude, 'latitude' => $latitude, 'address ' => $address ,'undefined'=>$undefined,]; $result = json_encode($properties); output($result); }
      
      





To look during debugging on JSON in which numbers are numbers, logical values ​​are logical, I am much more pleasant than just strings.



image



How about you?



All Articles