⬆️ ⬇️

Haxe and PHP: static typing, arrow functions, metaprogramming and much more

Hi, Habr! I bring to your attention the translation of the report of Alexander Kuzmenko from the recently held (June 14-15) conference of the Hong Kong Open Source Conference 2019.



image



Before joining the Haxe Foundation as a developer of the Haxe compiler, Alexander has been professionally programming in PHP for about 10 years, so he knows the subject of the report.



image



A small introduction to what Haxe is is a cross-platform toolkit for creating software, which includes:





image



PHP support in Haxe appeared quite a long time ago - back in 2008. In versions of Haxe up to 3.4.7, PHP 5.4 and higher was supported inclusively, and starting from the fourth version, Haxe supports PHP version 7.0 and higher.



image



You ask: why does a PHP developer use Haxe?

The main reason for this is the ability to use the same logic on both the server and the client.

Consider this example: you have a server written in PHP using the Laravel framework, and several clients written in JavaScript, Java, C #. In this case, to handle the network interaction between the server and the client (the logic of which is the same), you will need to write 4 implementations for each of the languages ​​used. But with the help of Haxe, you can write the network protocol code once and then compile / translate it for different platforms, saving considerable time on it.



image



Here is another example - a gaming application - a clone of Clash of Clans. Alexander participated in the development of a similar game: its server was written in PHP, the mobile client in C # (Xamarin), and the browser client in JavaScript using the Phaser framework. On the client and the server, one logic was processed - the so-called "boevka", which calculated the behavior of the players' units at the location. Initially, the code was written for each of the platforms separately. But over time (and the project has been developing for about 5 years), differences in its behavior on the server and on the clients accumulated. This was due to the fact that it was written by different people, each of whom implemented it in its own way. Because of this, there was no reliable way to detect cheaters, because the logic on the server behaved quite differently than on the client, and as a result, honest players suffered as well. the server could count them cheaters and not count the results of a fair fight.

In the end, it was decided to transfer the combat to Haxe, which made it possible to completely solve the problem with the cheaters, since Now the boevka logic behaved equally on all platforms. In addition, this solution has reduced the cost of further development of the combat system, because now there was enough one programmer familiar with Haxe, instead of three, each of whom would be responsible for his platform.



image



What are the differences between Haxe and PHP? In general, the Haxe syntax does not seem like something alien to a PHP programmer. Yes, it is different, but in most cases it will be very similar to PHP.

The slide shows a comparison of the code for outputting the string to the console. In Haxe, the code looks almost the same, except that to work with PHP functions, you need to import them (see the first line).



image



And this is how the generated PHP code looks in comparison with the handwritten code.

The Haxe compiler automatically adds a block of comments to the code with a description of the types of function arguments and return types, so the resulting code can be connected to a PHP project and auto-completion will work fine for it.



Consider some significant differences in the syntax of Haxe and PHP.



image



Let's start with the differences in the syntax of anonymous functions (for example, using them to sort an array).

The slide shows an anonymous function that captures and modifies the value of the local variable desc . In PHP, it is necessary to explicitly indicate which variables are available in the body of an anonymous function. In addition, to be able to change the value of a variable, you must add & before its name.

In Haxe, this need is eliminated, because the compiler itself determines which variables you refer to. In addition, in Haxe 4 there are arrow functions (a short form for describing anonymous functions), using which we can reduce our example with sorting the array to just one line.



image



Another difference in syntax is the differences in the description of the switch control construct. In PHP, the switch works the same as in C. In Haxe, it works differently:





image



In Haxe, everything is an expression, and it allows you to write more compact code. You can return a value from try / catch , if or switch without using the return keyword inside these constructs. In the above example with try / catch compiler "knows" that you want to return some value, and will be able to pass it from this construct.



image



PHP is gradually moving towards stricter typing, but Haxe already has strong static typing!

In the example above, we assign the variable s value obtained from the functionReturnsString() , which returns a string. Thus, the type of the variable s is a string. And if you try to pass it to the giveMeInteger() function, which giveMeInteger() for an integer as an argument, the Haxe compiler will generate an error about the type mismatch.

This example also demonstrates another important feature of Haxe - type inference (type inference) - the ability of the compiler to independently determine the types of variables, depending on what value it is assigned to.



image



For a programmer, this means that in most cases it is not necessary to explicitly specify the types of variables. So in the isSmall() function, the compiler will determine that the type of the argument a is an integer, since in the first line of the function body, we compare the value of a with an integer. Further, the compiler, based on the fact that we return true in the second line of the function body, determines that the return type is a Boolean value. And since Since the compiler has already determined the type of the return value, then when further attempts to return any other type from the function, it will generate a type mismatch error.



image



In Haxe, unlike PHP, there is no automatic type conversion. For example, in PHP it is possible to return a string from a function for which it is indicated that it returns an integer, in which case the string will be converted to a number (not always successfully) when the script is executed. And in Haxe, the same code simply won't compile - the compiler will generate a type mismatch error.



image



Another difference with Haxe is its extended type system, including:





All the types listed are compiled into PHP classes when compiled.



image



One of the main distinguishing features of Haxe is metaprogramming (in Haxe it is called macros), that is, the ability to automatically generate the source code of a program.

Macros are executed during the compilation of the program and are written in the usual Haxe.

Macros have full access to the abstract syntax tree, that is, they can read (search for the required expressions in it) and modify it.

Macros can generate expressions, modify existing types, and also create new ones.



image



In the context of PHP, macros can for example be used for routing. Let's say you have a simple class router that implements a method for displaying a page by its identifier, as well as a method for logging out of the system. Using a macro, you can generate code for the route() method, which, based on an http request, will redirect it to the appropriate method of the Router class. Thus, there is no need to manually write ifs for calls to each of the methods of this class (the macro will do this automatically when compiling the project in PHP). Note that the resulting code does not use reflection, does not require any special configuration files, or any additional tweaks, so it will work very quickly.



image



Another example of using macros is code generation for parsing and validating JSON. For example, you have a Data class, whose objects should be created on the basis of data obtained from JSON. This can be done using a macro, but since the macro has access to the structure of the Data class, in addition to parsing, you can generate code for JSON validation by adding an exception to exclude if there are no fields or data type mismatch. Thus, you can be sure that your application will not miss incorrect data received from users or from a third-party server.



It is also worth mentioning the important features of the implementation of some data types for the PHP platform, since if you do not take them into account, then you can face unpleasant consequences.



image



In PHP, binary safe ( binary safe ) strings, so in PHP, if you do not need Unicode support, the methods for working with strings work very quickly.

In Haxe, starting with the fourth version, strings support Unicode, so when they are compiled in PHP, the methods from the module for working with multibyte strings mbstring will be used, which means slow access to arbitrary characters in the string, slow calculation of the string length.

Therefore, if you don’t need Unicode support, you can use the methods of the php.NativeString class to work with strings, which will use native PHP strings.



image



The slide on the left shows PHP code that uses methods that support Unicode or not.

On the right is the equivalent Haxe code. As you can see, if you need Unicode support, you must use the methods of the String class, if not, then the methods of the php.NativeString class.



image



Another important point is the work with arrays.

In PHP, arrays are passed by value, and arrays support both numeric and string keys.

In Haxe, arrays are passed by reference and only support numeric keys (if string keys are required, then in Haxe, you should use the Map class for this). Also in the Haxe-arrays are not allowed "holes" in the indices (indices must go continuously).

It is also worth noting that writing to an array by index in Haxe is rather slow.



image



Here is the code for mapping an array using an arrow function. As you can see, the Haxe compiler is rather actively optimizing the PHP code output: the anonymous function in the resulting code is missing, instead its code is applied in a loop to each element of the array. In addition to map() this optimization is also applied to the filter() method.

Also, if necessary, in Haxe you can use the php.NativeArray class and the corresponding PHP methods for working with arrays.



image



Anonymous objects are implemented using the HxAnon class, which is inherited from the StdClass class from PHP.



image



In PHP, StdClass is a class whose instances turn everything we are trying to convert into an object. And it would be ideally suited for the implementation of anonymous objects if it were not for one specification feature: in Haxe, accessing a nonexistent field of an anonymous object should return null , and in PHP it throws out a warning. Because of this, I had to inherit from the standard class from PHP and add the magic method to it, which returns null when accessing non-existent properties.



image



Haxe can interact with code written in PHP. To do this, you have the following options (similar to the possibilities of interacting with JavaScript code):





image



Because PHP uses the classic OOP model, then writing externs for it is a fairly simple process. In fact, external classes for PHP classes are almost literal "translations" in Haxe, with the exception of some keywords.

As an example, the external code for the PHP class from the slide above will look like this:



image



Constants from the PHP class are "transformed" into static variables in the Haxe code (but with the addition of special meta tags).

The static variable $useBuiltinEncoderDecoder becomes the static variable useBuiltinEncoderDecoder .

This shows that external classes for PHP classes can be created automatically (Alexander plans to implement an external generator this year).



image



For PHP code inserts, the special module php.Syntax . The code added in this way is not subject to any transformations and optimizations by the Haxe compiler.

In addition to php.Syntax in Haxe, the possibility of using untyped-code has remained.

image



Also worth mentioning are the features of Haxe that are not in PHP:





More information about Haxe and its functions is available in its official manual .



')

Source: https://habr.com/ru/post/458184/



All Articles