kaitai-io / kaitai_struct

Kaitai Struct: declarative language to generate binary data parsers in C++ / C# / Go / Java / JavaScript / Lua / Nim / Perl / PHP / Python / Ruby
https://kaitai.io
4.03k stars 197 forks source link

PHP 7 support #16

Closed ghost closed 7 years ago

ghost commented 8 years ago

We would like to add support of PHP 7, we could assist you in that without knowledge of Scala and with knowledge of PHP. Is it a possible?

GreyCat commented 8 years ago

Definitely yes :) There are generally three big steps in adding support for new language that mostly require expertise in that language:

  1. Writing a runtime library
  2. Writing a "hello world" class example - i.e. how do you want the output to look
  3. Writing expression translator tests

Let's start with a runtime library? Can you port something like Java's or Ruby runtime to PHP?

ghost commented 8 years ago

Ok, I will try to port the runtime library and then I will return here.

GreyCat commented 8 years ago

You don't really need the full library done, a rough sketch is fine for a start.

Basically, we need to decide on a concept of "stream" and "reading" from it. I don't know PHP all that good, is there something like a common IO object that can be used to "read" stuff from both files and in-memory buffers there?

LogicAndTrick commented 8 years ago

I'm fairly familiar with PHP but just normal website stuff so I've not dealt with binary streams in it before. It looks like PHP treats all streams as files, you can fopen() a file path, or use php://memory for an in-memory stream. From there you need to use the fread, fseek, etc methods.

Found some stuff that might be useful to implement the runtime:

I think there might need to be some structural changes in the compiler for PHP, as it doesn't support nested/inner classes. There's anonymous classes in PHP7 which are about equivalent to Java's anonymous classes, but they're single-use so I don't think they'd work.

The inner classes would likely need to go side-by side:

// Not allowed
class PhpClass1 {
    class PhpClass2 { ... }
}

// Allowed
class PhpClass1 { ... }
class PhpClass2 { ... }
GreyCat commented 8 years ago

Looks like a way to go then, probably shouldn't be any problems with streams.

Last time I've seen PHP was around PHP3, so my knowledge is, well, very dated. What's generic approach for distribution of libraries in PHP nowadays? Are there a practice of doing "class libraries" (to implement stuff like KaitaiStruct + KaitaiStream), or a module-based approach is preferred, with just lots of functions imported?

Lack of nested classes might be a problem, yeah. Technically, C++ compiler already includes machinery to propagate full qualified name of the class like PhpClass1::PhpClass2, so we could render it as Php1Class__PhpClass2 or something along these lines.

ghost commented 8 years ago

There is streamWrapper class. We can extend this class and implement required methods then we can register the wrapper object like this:

class MyStream extend \streamWrapper {
    // implementation of the streamWrapper members here
}
stream_wrapper_register("protocol", "MyStream");

Here is an example from PHP docs for working with variable (I assume string variable $myvar) as stream:

<?php
$existed = in_array("var", stream_get_wrappers());
if ($existed) {
    stream_wrapper_unregister("var");
}
stream_wrapper_register("var", "VariableStream");
$myvar = "";

$fp = fopen("var://myvar", "r+");

fwrite($fp, "line1\n");
fwrite($fp, "line2\n");
fwrite($fp, "line3\n");

rewind($fp);
while (!feof($fp)) {
    echo fgets($fp);
}
fclose($fp);
var_dump($myvar);

if ($existed) {
    stream_wrapper_restore("var");
}
ghost commented 8 years ago

by @LogicAndTrick:

MIT licensed binary reader class - perhaps a good starting point?

Ok, I will look into the code and check how it can be used.

by @GreyCat:

What's generic approach for distribution of libraries in PHP nowadays?

The generic approach is using the composer tool and composer packages (it is similar to npm in Node.js). To become a composer package, a project should have a composer.json file, for example the referenced above library has it. When the project has this file it can installed with the composer install command.

Are there a practice of doing "class libraries" (to implement stuff like KaitaiStruct + KaitaiStream), or a module-based approach is preferred, with just lots of functions imported?

Usually classes and namespaces are used, the https://github.com/mdurrant/php-binary-reader has pretty usual structure, as other example see the https://github.com/Seldaek/monolog.

Lack of nested classes might be a problem, yeah. Technically, C++ compiler already includes machinery to propagate full qualified name of the class like PhpClass1::PhpClass2, so we could render it as Php1Class__PhpClass2 or something along these lines.

Why the nested classes can be necessary? Can the namespaces be used, for e.g. \PhpClass1\PhpClass2?


As addition for the my previous comment about the streamWrapper: some examples can be found in Drupal, see https://github.com/drupal/drupal/tree/8.2.x/core/lib/Drupal/Core/StreamWrapper.

LogicAndTrick commented 8 years ago

I don't think a custom streamWrapper implementation is needed for the runtime, as there's already native wrappers for file and memory streams and that's all Kaitai needs.

Namespaces are an option for the nested classes, yes. Namespaces can't be nested in PHP either so there will still likely need to be changes to the compiler to work with that.

// Not allowed
namespace One {
    namespace Two { ... }
}

// Allowed
namespace One { ... }
namespace One\Two { ... }
ghost commented 8 years ago

@LogicAndTrick ok.

The https://github.com/morpho-os/kaitai_struct_php_runtime repo was created for the temp implementation.

GreyCat commented 8 years ago

There is streamWrapper class.

Might be a way to go. Alternatively, you might want to consider a completely different approach: just do two completely different internal classes with a same API: one that reads from the fopen-based stream and another that reads from a in-memory buffer (that would be PHP's string, if I'm not mistaken). I see that https://github.com/mdurrant/php-binary-reader uses the latter approach, just reading from the string.

Ok, I will look into the code and check how it can be used.

I've took a look and it looks like a good thing to start from! Basically, it almost does everything we need already — except for:

  1. we use modeless endianness handling (i.e. just separate methods to read big-endian / little-endian - the compiler handles that internally, no need for a stream class to handle endianness as a state)
  2. process_* methods for stuff like XORs, ROL/ROR, etc

However, may be it's just me, but internally it looks fairly overengineered - it rolls a whole distinct class like Int32 where just two lines of code with unpack call would have probably sufficed. I wonder about the probable performance issues too.

There's a huge benefit there too: php-binary-reader library already implements per-bit unaligned reading, that we are still discussing in #9 and #12.

ghost commented 8 years ago

I don't think a custom streamWrapper implementation is needed for the runtime, as there's already native wrappers for file and memory streams and that's all Kaitai needs.

PHP native wrapper don't have methods for Reading and Processing. This is why we probably need extends the native PHP \streamWrapper class.

I am looking on the implementations of the Struct in Java, C#, Ruby and Python and they are very simple - they just accept KaitaiStream io as constructor argument.

Could you describe why?

GreyCat commented 8 years ago

The Struct class exists only as a common base for all compiler-generated classes. And the only thing in they have in common is generally that they have _io that can be accessed to get to the stream associated with the object.

Technically, they all also need to have:

GreyCat commented 8 years ago

@markbook2 Also, while designing the Stream class, please note this checklist of methods and groups. Please try to keep them in the same order and groups :)

LogicAndTrick commented 8 years ago

@markbook2: I think there might be a misunderstanding - from what I can see, the only reason to implement a streamWrapper is to register it as a custom protocol in PHP. The class doesn't actually exist - it's just an interface, so you can't extend it, only write your own custom implementation. From the PHP docs:

This is NOT a real class, only a prototype of how a class defining its own protocol should be.

What we need is a custom stream class that implements the Kaitai stream API, but this will be unrelated to streamWrapper and will be fairly similar to the BinaryReader class in php-binary-reader. All you need to switch between in-memory and file streams is something like this:

if ($in_memory) {
    $stream = fopen('php://memory', 'br+');
    fwrite($stream, $in_memory_data);
    rewind($stream);
} else {
    $stream = fopen($file_name);
}

@GreyCat: It's not just you, I thought the same thing about the unnecessary classes. I think the PHP runtime will be fairly similar to the Ruby runtime, considering they have very similar unpack methods.

GreyCat commented 8 years ago

@LogicAndTrick OTOH, all our runtimes are bound to become somewhat more complicated, as soon as we'll start implementing unaligned bit reading. However, I'd vote to keep them separate anyway - i.e. keep regular "aligned" versions like read_u4le and add separate "unaligned" versions like read_u4le_unaligned which will keep track of stream's big pointer and will be obviously much more complicated than just a 1-liner with an unpack call.

GreyCat commented 8 years ago
if ($in_memory) {
    $stream = fopen('php://memory', 'br+');
    fwrite($stream, $in_memory_data);
    rewind($stream);
} else {
    $stream = fopen($file_name);
}

Umm... Wouldn't that double the amount of RAM required?

LogicAndTrick commented 8 years ago

Unaligned data: It depends on how it's implemented in the KSY format. I think it might be reasonable to modify the existing read methods to support sub-byte alignment, and then the only new API methods would be to modify the bit pointer. The unaligned versions work in all cases, even when it happens to be aligned.

It also depends on the performance impact, of course. The C# runtime calls ReadBytes before converting the data, so that method would be the only place that needs to change to support unaligned data (and it could use a faster implementation when reading data that's byte-aligned)

Double memory: probably! I hadn't thought about that. If it helps, the php://temp protocol transparently uses the filesystem when a certain threshold is exceeded (default 2MB). Now I get why a custom stream wrapper might be needed.

ghost commented 8 years ago

Also, while designing the Stream class, please note this checklist of methods and groups. Please try to keep them in the same order and groups :)

Useful info, it would be good to add the reference to it here: https://github.com/kaitai-io/kaitai_struct/wiki/Kaitai-Struct-stream-API.

I have found that the checklist has different methods then the Kaitai-Struct-stream-API:

GreyCat commented 8 years ago

Alas, our documentation has still a long way to go :( I'll try to fix wiki page to match the checklist.

GreyCat commented 8 years ago

@markbook2 I see that you've done lots of basic work done on the PHP KS streaming API. Could you switch temporarily to task 2: "Writing a "hello world" class example"? That would allow me to start a basic KS-to-PHP compiler.

Basically, you need to write manually output of the compiler for hello_world.ksy. Try to compile it into any supported language (by the way, what are you're most comfortable with, besides PHP?) and let me know how you want it to look, translated in PHP.

ghost commented 8 years ago

@GreyCat: Do you mean by "Hello World" the code similar to the following C# code:

Gif g = Gif.FromFile("path/to/some.gif");
Console.WriteLine("width = " + g.LogicalScreen.ImageWidth);
Console.WriteLine("height = " + g.LogicalScreen.ImageHeight);

?

If yes, then it can be very similar for PHP:

$g = Gif::fromFile("path/to/some.gif");
echo "width = " . $g->logical_screen->image_width;
echo "height = " . $g->logical_screen->image_height;

I would like to note on the following: avoiding of the automatic translation of the field names to camelCase (or CamelCase), i.e. the object's fields should be equal to the field names in the .ksy file - if camelCase (or CamelCase) will be required the camelCase (or CamelCase) can be used in the .ksy file.


It would be good to provide full examples of the generated classes from .ksy file for the all target languages, for example for the gif.ksy, so I and others could see the full code and better understand the context of the usage. Something like this for C#:

For the following input file gif.ksy:
meta:
  id: gif
  file_extension: gif
  endian: le
seq:
  - id: header
    type: header
  - id: logical_screen
    type: logical_screen
types:
  header:
    seq:
      - id: magic
        contents: 'GIF'
      - id: version
        size: 3
  logical_screen:
    seq:
      - id: image_width
        type: u2
      - id: image_height
        type: u2
      - id: flags
        type: u1
      - id: bg_color_index
        type: u1
      - id: pixel_aspect_ratio
        type: u1

The call:
> kaitai-struct-compiler gif.ksy
will produce the Gif.cs file with the following content (link to Gif.cs here).

Then Git.cs can be called like this from the your code:

Gif g = Gif.FromFile("path/to/some.gif");
Console.WriteLine("width = " + g.LogicalScreen.ImageWidth);
Console.WriteLine("height = " + g.LogicalScreen.ImageHeight);

The main page contains the similar information but it is not so simple to understand the whole picture.

ghost commented 8 years ago

Basically, you need to write manually output of the compiler for hello_world.ksy. Try to compile it into any supported language (by the way, what are you're most comfortable with, besides PHP?) and let me know how you want it to look, translated in PHP.

Ok. Regarding the most comfortable with language - for writing Struct.php and Stream.php I use Ruby, Java and C# as reference but may use others too.

ghost commented 8 years ago

@GreyCat The HelloWorld was added, see https://github.com/morpho-os/kaitai_struct_php_runtime/blob/master/hello-world/php/HelloWorld.php.

GreyCat commented 8 years ago

Thanks! I believe that normally people wouldn't want to generate classes in Kaitai namespace - that probably means that extends Struct should be extends Kaitai::Struct?

ghost commented 8 years ago

Then it should be changed to:

<?php
namespace Kaitai\Struct;

use Kaitai\Struct;
use Kaitai\Stream;

class HelloWorld extends Struct {
// ...
GreyCat commented 8 years ago

Does it mean that someone who will name their type "struct" or "stream" will yield:

class Struct extends Struct {

and everything will explode?

ghost commented 8 years ago

Such situation can be resolved like this:

namespace Foo;

class Struct {

}

namespace Bar;

use Foo\Struct as FooStruct;

class Struct extends FooStruct {

}

$foo = new Struct;
var_dump($foo);
/* Output:
object(Bar\Struct)#4 (0) {
}
*/

See http://php.net/manual/en/language.namespaces.importing.php

GreyCat commented 8 years ago

Why can't we just use full qualified name, something like Kaitai\Struct and Kaitai\Stream directly?

ghost commented 8 years ago

@GreyCat Could you provide an example, i.e. concrete chunk of the code to help me better understand the case? In general the full qualified names can be used but general practice is importing each class at the top of file and use short name in the code.

As you said

normally people wouldn't want to generate classes in Kaitai namespace - that probably means that extends Struct should be extends Kaitai::Struct

So you think that peoples will want to use \Kaitai\Struct\Struct and \Kaitai\Struct\Stream, but not the \Kaitai\Struct and the \Kaitai\Stream, right?

GreyCat commented 8 years ago

@markbook2 I've started working on the compiler and one of the major things for me to decide for a new language is how to name KaitaiStruct & KaitaiStream types. Ideally, I need names usable everywhere in generated code (no matter the place, no matter if user wants to have classes named "Struct" or "Stream" in his namespace, etc, etc.

Many languages have fully qualified names - they're ideal for such purpose. So, I believe, it's safe to call them \Kaitai\Struct\Struct and \Kaitai\Struct\Stream everywhere in PHP code and thus we won't be afraid of possible name clashes, varied named on different levels of class declartions, etc?

GreyCat commented 8 years ago

By the way, could you take a look at the questions I've asked at https://github.com/morpho-os/kaitai_struct_php_runtime/commit/398947d0d54df144a5450c405617387feb229323 ? The main question that remains now is about that mysterious __get.

GreyCat commented 8 years ago

I've pushed php branch into compiler - feel free to check it out and play with it. Are you ok with building it and running scripts from tests repo?

ghost commented 8 years ago

Are you ok with building it and running scripts from tests repo?

Could you provide info how the tests can be run?

I have successfully rebuilt the compiler and got the HelloWorld.php file. It would be good to fix the syntax and other errors and make it as close as possible to the original implementation. The original implementation is very similar to the Java and C#, so it does not require many changes. If you think that the Struct or Stream class names can affect the user's classes the prefix Kaitai can be added as it done for the C# and Java, i.e. the fully qualified names would be \Kaitai\KaitaiStream and \Kaitai\KaitaiStruct (use the namespace at the top of file for that).

GreyCat commented 8 years ago

Could you provide info how the tests can be runned?

Sure - please take a look at tests README for the detailed explanation. A very short version: you just check out whole [central kaitai_struct repo], do cd tests and run ./build-compiler && ./build-formats.

On the next stages we'll need actual tests cases ported to PHP. I guess it won't be too hard - you can take a look at test cases in Python or test cases in Ruby - we need something along the lines.

I have successfully rebuilt the compiler and got the HelloWorld.php file.

Ok, that's great news! I hope we'll get it to be syntactically correct and make it pass our first test in PHP in a few iterations.

fully qualified names would be \Kaitai\KaitaiStream and \Kaitai\KaitaiStruct

I'd prefer to settle for \Kaitai\Struct\Struct and \Kaitai\Struct\Stream if it's possible and not against language traditions. The basic idea is that "Kaitai" is organization/team name, "Kaitai Struct" is thus a project name, and third level are the names of the classes. Would that be ok?

GreyCat commented 8 years ago

Ok, more news from me: I've got very basic PHP testing up and running. It is based on command-line version of phpunit (it relies on phpunit being available in system-wide install), and one can execute ./run-php in /tests repo to get it running.

The test spec itself is a pretty straightforward port from all other languages:

<?php

namespace Kaitai\Tests;

class HelloWorldTest extends \PHPUnit_Framework_TestCase {
    public function test() {
        $r = HelloWorld::fromFile('src/fixed_struct.bin');
        $this->assertEquals($r->one, 0x50);
    }
}

and it is supported by _bootstrap.php, which basically:

  1. forcefully loads KaitaiStruct and KaitaiStream runtimes
  2. adds a very simple autoloader that checks if the classes requested start with Kaitai\Tests\ and then tries to load them from compiled/php/$testName.php.

Probably there is a better way to do it, feel free to fix.

ghost commented 8 years ago

Looks good.


I have a suggestion: can we move the \Kaitai\Struct\Struct and \Kaitai\Struct\Stream under the \Kaitai namespace, so the full class names would be \Kaitai\Stream and \Kaitai\Struct? For e.g. if C# classes would be converted to PHP they would be \Kaitai\KaitaiStruct and \Kaitai\KaitaiStream. The prefix "Kaitai" for the classes seems like redundant for PHP, this is why the \Kaitai\KaitaiStruct can be renamed to just \Kaitai\Struct and the \Kaitai\KaitaiStream to the \Kaitai\Stream. There is one note here: in PHP there is no keyword "Struct" but may be added in future versions, this is why the Kaitai{Struct,Stream} can be not renamed and left as \Kaitai\KaitaiStream and \Kaitai\KaitaiStruct.

After applying these changes to the HelloWorld, it would be:

class HelloWorld extends \Kaitai\Struct {

    public function __construct(\Kaitai\Stream $io, \Kaitai\Struct $parent = null, HelloWorld $root = null) {
        parent::__construct($io, $parent, $root);
        $this->_parse();
    }
    private function _parse() {
        $this->one = $this->_io->readU1();
    }
    protected $one;
    protected $_root;
    protected $_parent;
    public function one() { return $this->one; }
    public function _root() { return $this->_root; }
    public function _parent() { return $this->_parent; }
}

The class Struct can be made abstract as in C#:

abstract class Struct {
// code here
}

In the _bootstrap.php the include can be replaced with require.


I have noticed that there are nested classes which PHP does not support: File tests/compiled/BufferedStruct.php:

    class BufferedStruct.Block extends \Kaitai\Struct\Struct {

The dot . is not allowed here. There is a project - PHP Parser, it works pretty well. See how it handles the nested classes - https://github.com/nikic/PHP-Parser/tree/master/lib/PhpParser/Node. The each Node corresponds to a token from the PHP language. In similar manner the generated classes like HelloWorld can be placed under the \Kaitai\Struct namespace, for example - \Kaitai\Struct\HelloWorld or under some other namespace, e.g. \Kaitai\Generated*. With such approach the parent class will be the \Kaitai\Struct and child classes will be \Kaitai\Struct\SomeGeneratedClass.

The syntax of the generated classes can be checked with the command: php -l $filePath.

ghost commented 8 years ago

I have left the sentence:

I'd prefer to settle for \Kaitai\Struct\Struct and \Kaitai\Struct\Stream if it's possible and not against language traditions. The basic idea is that "Kaitai" is organization/team name, "Kaitai Struct" is thus a project name, and third level are the names of the classes. Would that be ok?

Due that, please ignore partially the my previous suggestion about moving classes under the root \Kaitai namespace if you would like to use it as top level namespace for the vendor/organization.

Some PHP projects include vendor in the names of classes, e.g. Drupal, Zend Framework has the 'Zend' prefix for all its packages. Some PHP projects don't include vendor name in theirs classes.

If you want to use the vendor/organization name as the root namespace then the generated classes can be placed under the \Kaitai\Struct\Struct\ or to the \Kaitai\Struct\Generated\.

There is another option - use the KaitaiStruct namespace as the root namespace name.

All options are equally preferable so it is your decision which namespace to use.

GreyCat commented 8 years ago

Ok, then let's settle for:

The next step: could you fix test & runtime to make hello_world.ksy work, or tell me what needs to be fixed in generated class?

ghost commented 8 years ago

Added the fixed test - https://github.com/morpho-os/kaitai_struct_php_runtime/tree/master/kaitai_struct-fix

Structure of directories inside the kaitai_struct-fix/ directory is the same as for the project after cloning.

GreyCat commented 8 years ago

Wow. Why don't you just do normal fork + pull request? They would be tons easier, isn't it?

ghost commented 8 years ago

Could you create the kaitai-io/kaitai_struct_php_runtime repo?

GreyCat commented 8 years ago

I thought we should just transfer ownership of morpho-os/kaitai_struct_php_runtime to kaitai-io, thus creating kaitai-io/kaitai_struct_php_runtime — but, on the second thought, I guess it's better to create a fresh repo. morpho-os/kaitai_struct_php_runtime has already lots of things committed that do not belong there (like hello-world, kaitai_struct-fix, and especially test/KaitaiTest/Struct/_files/bash (which is additional pain in the ass, because it's a binary build of a GPL application, thus you need to add more clauses into licensing info + add the sources of the binary you distribute or at least add the link). Plus, it's a huge bloat due to that in the repository, take a look:

So, I'll create a fresh runtime repo and import your current stuff there then.

GreyCat commented 8 years ago

More thoughts on your changes:

  1. You have deleted end-of-file newlines for PHP files. This directly contradicts PSR-2, section 2.2 - "All PHP files MUST end with a single blank line". Please don't do that.
  2. I don't think that adding a listing of all test case classes in _bootstrap.php is a good idea. It would be an additional pain to support, and, as far as I can tell, doesn't bring any additional benefits.

That said, I've merged php branch into master, and added thus PHP test generation to Travis builds. ./run-php seems to work, but compiled file is broken right now:

PHPUnit 5.4.6 by Sebastian Bergmann and contributors.

PHP Fatal error:  Declaration of HelloWorld::_parent() must be compatible with Kaitai\Struct\Struct::_parent(): Kaitai\Struct\Struct in /home/greycat/git/kaitai_struct/tests/compiled/php/HelloWorld.php on line 21

I'll try to fix that. Probably I'll just replace derived parent types with regular \Kaitai\Struct\Struct for now.

ghost commented 8 years ago

GreyCat, thanks.

I don't follow all PSR-2 recommendations. There is the https://github.com/FriendsOfPhp/PHP-CS-Fixer which can take care about such things. I can setup it for you if you think that files should have empty line at the end.

This error:

> PHP Fatal error:  Declaration of HelloWorld::_parent() must be compatible with Kaitai\Struct\Struct::_parent(): Kaitai\Struct\Struct in /home/greycat/git/kaitai_struct/tests/compiled/php/HelloWorld.php on line 21

was there before I have fixed it, if the source code in generated and library files will be the same as in the morpho-os/kaitai_struct_php_runtime then the error should go away.

GreyCat commented 8 years ago

I'm ok with any coding style as long as it's written down. PSR-1+PSR-2 is available, but you haven't published yours. At the very least, git will issue a warning for every abscene of newline at EOF.

I've noticed that you've written current test code in a way that generated (compiled/php) files are placed in root namespace. I propose to have them in the same namespace as test specs — i.e. \Kaitai\Struct\Tests. I've added --php-namespace argument to compiler to do that and build-formats is already set up to use it. Would that be ok or there's some good reason to keep generated PHP files in root namespace?

ghost commented 8 years ago

I prefer the same coding standards as described in the PSR-1,2, except the following rules from PSR-2:

From section 1:

Opening braces for classes MUST go on the next line, and closing braces MUST go on the next line after the body. Opening braces for methods MUST go on the next line, and closing braces MUST go on the next line after the body.

From section 2.2:

All PHP files MUST end with a single blank line.


Would that be ok or there's some good reason to keep generated PHP files in root namespace?

There is no a reason why they should be in the root namespace. The --php-namespace and the \Kaitai\Struct\Tests is fine.

ghost commented 8 years ago

There are the following errors - things to fix in the compiler and generated classes to make the HelloWorld test pass:

1) Don't add the leading slash for the namespaces, so the top of the HelloWorld.php file would look like:

<?php
namespace Kaitai\Struct\Tests; // Note: no leading slash here (not \Kaitai\...)

2) Optional, but recommended fix - the following code can be removed safely from the \Kaitai\Struct\Tests\HelloWorld:

    protected $_root;
    protected $_parent;

as these properties/fields already present in the parent \Kaitai\Struct\Struct class.

GreyCat commented 8 years ago

Got it, thanks. Will do now.

GreyCat commented 8 years ago

Hurrah, our first test in PHP officially passes:

PHPUnit 5.4.6 by Sebastian Bergmann and contributors.
..                                                                  2 / 2 (100%)
Time: 20 ms, Memory: 4.00MB
OK (2 tests, 2 assertions)

From now on, there are several ways where we should head:

    full("foo.inner.baz", FooBarProvider, CalcIntType, Map(
      CSharpCompiler -> "Foo.Inner.Baz",
      JavaCompiler -> "foo().inner().baz()",
      JavaScriptCompiler -> "this.foo.inner.baz",
      PythonCompiler -> "self.foo.inner.baz",
      RubyCompiler -> "foo.inner.baz"
    )),

you would probably want to add PHPCompiler -> "foo->inner->baz" or whatever's the right answer for PHP would be.

ghost commented 8 years ago

@GreyCat great. I could try port additional test specs from other languages to PHP.