This is the XP Framework's development checkout.
If you just want to use the XP Framework, grab a release using composer require xp-framework/core
. If you wish to use this development checkout, clone this repository instead.
The entry point for software written in the XP Framework is not the PHP interpreter's CLI / web server API but either a command line runner or a specialized web entry point. These runners can be installed by using the following one-liner:
$ cd ~/bin
$ curl -sSL https://baltocdn.com/xp-framework/xp-runners/distribution/downloads/i/installer/setup-9.1.0.sh | sh
To use the the XP Framework development checkout, put the following in your ~/bin/xp.ini
file:
use=/path/to/xp/core
Finally, start xp -v
to see it working:
$ xp -v
XP 12.4.1-dev { PHP/8.4.6 & Zend/4.4.6 } @ Windows NT SURFACE 10.0 build 26100 (Windows 11) AMD64
Copyright (c) 2001-2025 the XP group
FileSystemCL<./src/main/php>
FileSystemCL<./src/test/php>
FileSystemCL<./src/main/resources>
FileSystemCL<./src/test/resources>
FileSystemCL<.>
The XP Framework runs scripts or classes.
Save the following sourcecode to a file called ageindays.script.php
:
<?php namespace examples;
use util\{Date, Dates};
use util\cmd\Console;
$span= Dates::diff(new Date($argv[1]), Date::now());
Console::writeLine('Hey, you are ', $span->getDays(), ' days old');
Now run it:
$ xp ageindays.script.php 1977-12-14
Hey, you are 16015 days old
Alternatively, you can put this code inside a class and give it a static main method. This way, you can use features like inheritance, trait inclusion etcetera. This time, save the code to a file called AgeInDays.class.php
.
<?php
use util\{Date, Dates};
use util\cmd\Console;
class AgeInDays {
public static function main(array $args): int {
$span= Dates::diff(new Date($args[0]), Date::now());
Console::writeLine('Hey, you are ', $span->getDays(), ' days old');
return 0;
}
}
Note the arguments have shifted by one: If you want the class' name, simply use self::class
!
$ xp AgeInDays 1977-12-14
Hey, you are 16015 days old
To contribute, use the GitHub way - fork, hack, and submit a pull request!
Enjoy!
core's People
core's Issues
Type union parsing
# Is
$ xp -w '\lang\Type::forName("string|string[]")'
lang.ArrayType<string|string[]>
# Expected
$ xp -w '\lang\Type::forName("string|string[]")'
lang.TypeUnion<string|string[]>
Missing help topics
$ xp help write
No help topic named xp/runtime/write.md
- ar
- dump
- eval
- help
- list
- run
- version
- write
PHP 8 compatibility
Looks good after PHP8 was branched off a week ago.
$ XP_RT=master xp -v
XP 10.0.0-dev { PHP/8.0.0-dev & Zend/4.0.0-dev } @ Windows NT SLATE 10.0 build 17134...
Copyright (c) 2001-2019 the XP group
FileSystemCL<./src/main/php>
FileSystemCL<./src/test/php>
FileSystemCL<./src/main/resources>
FileSystemCL<./src/test/resources>
ArchiveCL<./test.xar>
FileSystemCL<.>
$ XP_RT=master xp test src/test/config/unittest/core.ini
# ...
♥: 2198/2223 run (25 skipped), 2198 succeeded, 0 failed
Memory used: 10967.42 kB (11992.66 kB peak)
Time taken: 4.153 seconds
PHP Nightly failing test with __PHP_Incomplete_Class
See https://travis-ci.org/xp-framework/core/jobs/155730531
F unittest.TestAssertionFailed(test= net.xp_framework.unittest.reflection.ClassLoaderTest::newInstance__PHP_Incomplete_Class, time= 0.000 seconds) {
unittest.AssertionFailedError{ Expected lang.ClassCastException not caught }
at unittest.TestSuite::run() [line 388 of Runner.class.php]
at xp.unittest.Runner::run() [line 398 of Runner.class.php]
at xp.unittest.Runner::main() [line 376 of class-main.php]
}
Casting to int: Uninitialized string offset: 1
Primitive::$INT->cast('2')
// Exception lang.IndexOutOfBoundsException (Uninitialized string offset: 1)
/cc @johannes85
Deprecate curly brace syntax for accessing array elements and string offsets
Secret::random()
In my code I needed a random initial password, so I used base64_encode(openssl_random_pseudo_bytes(12))
. I think a good place for this might be the util.Secret
class:
$secret= Secret::random(12);
$value= $secret->reveal();
See also http://php.net/manual/en/function.random-bytes.php (PHP 7 only!)
Use of undefined constant STR_ENC
$ xp -w '(new \lang\types\Character(8420))->getBytes()'
Uncaught exception: Exception lang.reflect.TargetInvocationException (xp\runtime\Dump::main)
at lang.types.Character::getBytes() [line 104 of Character.class.php] Use of undefined constant STR_ENC - assumed 'STR_ENC'
at lang.types.Character::getBytes() [line 106 of Character.class.php] Use of undefined constant STR_ENC - assumed 'STR_ENC'
at <main>::iconv() [line 106 of Character.class.php] iconv(): Wrong charset, conversion from `STR_ENC' to `UTF-8' is not allowed
at lang.reflect.Method::invoke(NULL, array[1]) [line 248 of class-main.php]
Caused by Exception lang.IllegalArgumentException (Expected either Byte[], char[], int[] or string but was boolean)
at lang.types.Character::getBytes() [line 104 of Character.class.php] Use of undefined constant STR_ENC - assumed 'STR_ENC'
at lang.types.Character::getBytes() [line 106 of Character.class.php] Use of undefined constant STR_ENC - assumed 'STR_ENC'
at <main>::iconv() [line 106 of Character.class.php] iconv(): Wrong charset, conversion from `STR_ENC' to `UTF-8' is not allowed
at lang.types.Bytes::__construct() [line 107 of Character.class.php]
at lang.types.Character::getBytes() [line 1 of Dump.class.php(45) : eval()'d code]
at <main>::eval() [line 45 of Dump.class.php]
at xp.runtime.Dump::main(array[2]) [line 0 of StackTraceElement.class.php]
... 2 more
Endless loop in io.Path::relativeTo()
# Works as expected
$ xp -w "use io\Path; (new Path('C:\Windows'))->relativeTo(new Path('C:'))"
Windows
# Hangs in an endless loop
$ xp -w "use io\Path; (new Path('C:\Windows'))->relativeTo(new Path('c:'))"
Generic classes and namespaces
The following code does not call the hashCode()
method:
$ht= create('new util.collections.HashTable<string, lang.Generic>');
$ht->put('hello', newinstance('lang.Object', [], '{
function hashCode() { var_dump(__FUNCTION__); return parent::hashCode(); }
}'));
Changing the instanceof
tests inside util.collections.HashTable to use the fully qualified class name, \lang\Generic
, makes the code work.
Iterable type hint breaks newinstance()
abstract class Base {
public abstract function fixture(iterable $arg);
}
newinstance(Base::class, [], [
'fixture' => function(iterable $arg) { }
]);
Uncaught error: Compile error (Declaration of Base▒1::fixture($args) must be compatible with Base::fixture(iterable $args))
Since PHP 7.1 - see https://wiki.php.net/rfc/iterable
Function mcrypt_module_open() is deprecated
See https://travis-ci.org/xp-framework/core/jobs/152229674 (PHP 7.1)
XAR files: syntax error, unexpected end of file
$ XP_RT=7.4 xp -cp test.xar xp.unittest.Runner src/test/config/unittest/core.ini
Uncaught exception: ParseError (syntax error, unexpected end of file)
at <source> [line 277 of xar://.\test.xar?xp/unittest/Runner.class.php]
at <main>('src/test/config/unittest/core.ini') [line 0 of xp.unittest.Runner]
at lang.AbstractClassLoader->loadClass0('xp.unittest.Runner') [line 444 of lang.base.php]
at <main>::{closure}('xp\\unittest\\Runner') [line 0 of (unknown)]
at <main>::spl_autoload_call('xp\\unittest\\Runner') [line 0 of (unknown)]
at <main>::is_callable(array[2]) [line 369 of class-main.php]
With PHP 7.3, no error occurs.
var not assignable from var?!
If the apidoc comment is added again at this position, the test fails with:
Exception lang.ClassCastException (Cannot cast string to the function(var): unittest.assert.Value type: Parameter #1 not a var type: var)
The reason is that the two types don't reflect the same Type::$VAR
instance, and isAssignableFrom()
tests with self::$VAR === $this
. Cannot create a reproduce case at the moment, but the issue is solveable by prevent duplicate initialization of Type::$VAR
.
Feature request: Unicode icons for unittest
Use ✓ for successful builds and ✗ for errors.
Prefer "float" over "double"
function similarity(string $a, string $b): double {
similar_text($a, $b, $p);
return $p;
}
The function above yields TypeError (Return value of related\similarity() must be an instance of double, float returned, while (double)
-casts work just as well as (float)
, and gettype(1.5)
even returns double (one of PHP's inconsistencies...)
- Add lang.Primitive::$FLOAT, deprecate lang.Primitive::$DOUBLE
- Change casts inside code
- Change
@param
/@return
and syntactic type hints - Replace doubleval() with floatval()
- Replace is_double() with is_float()
PHP 7.1.0 segmentation fault
See for example this build:
/home/travis/build.sh: line 45: 3104 Segmentation fault (core dumped)
./xp -cp test.xar xp.unittest.Runner $i
xar command
The xar c[reate]
command does not work with XP 7.0 as it uses io.collections
classes:
$ xar cvf test.xar ../unittest/src/main/php/=.
Uncaught exception: Exception lang.reflect.TargetInvocationException (xp.xar.Runner::main)
at lang.reflect.Method::invoke(NULL, array[1]) [line 350 of class-main.php]
Caused by Exception lang.Error (Class 'io\collections\iterate\UriMatchesFilter' not found)
at ...
TODO:
-
⚠️ Fix the original command - 💚 Provide a subcommand - see xp-framework/rfc#303
Fatal error location swallowed
Using PHP7, fatal error locations are swallowed:
$ xp -cp ../sequence/src/main/php/ Seq ini
Uncaught exception: Exception lang.reflect.TargetInvocationException (Seq::main)
at lang.reflect.Method::invoke(NULL, array[1]) [line 305 of class-main.php]
Caused by Exception lang.Error (Call to a member function key() on array)
In PHP5 and PHP7, native exception origins are swallowed:
$ XP_RT=5.6 xp -w 'new ReflectionClass("a")'
Uncaught exception: Exception lang.reflect.TargetInvocationException (xp.runtime.Dump::main)
at lang.reflect.Method::invoke(NULL, array[1]) [line 305 of class-main.php]
Caused by Exception lang.XPException (Class a does not exist)
MockProxyBuilder does not respect namespaces
When mocking a class that uses a typehint from a namespaced class, the namespace will not correctly be propagated to the mock, resulting in PHP notices when running unittests. The following script is a simple reproducing case:
<?php
class Example extends \lang\Object {
public static function main($args) {
create(new \unittest\mock\MockRepository())->createMock('Example');
\util\cmd\Console::writeLine(\xp::stringOf(\xp::$errors));
}
private function acceptLong(\lang\types\Long $long) {
}
}
Gives the following output:
[
dyn://MockProxy?0 => [
1 => [
Declaration of MockProxy?0::acceptLong() should be compatible with that of Example::acceptLong() => [
class => null
method => "include"
cnt => 1
]
]
]
]
The MockProxyBuilder generates this source code:
class MockProxy?0 extends Example implements IMockProxy, IMock {
private $_h= null;
public function __construct($handler) {
$this->_h= $handler;
}
public function acceptLong(Long $long) { return $this->_h->invoke($this, 'acceptLong', func_get_args()); }
public function _replayMock() { return $this->_h->invoke($this, '_replayMock', func_get_args()); }
public function _isMockRecording() { return $this->_h->invoke($this, '_isMockRecording', func_get_args()); }
public function _isMockReplaying() { return $this->_h->invoke($this, '_isMockReplaying', func_get_args()); }
public function _verifyMock() { return $this->_h->invoke($this, '_verifyMock', func_get_args()); }
}
Generics and namespaces
use lang\Object;
#[generic(self= 'T')]
class Test extends Object {
}
This does not work as expected - the name Object
gets resolved to the current namespace instead of the use
statement being honored - /cc @pdietz
newinstance() broken for simple class names
# kiesel at vb-kiesel in ~/test [17:57:26]
$ cat > mynamespace/Test.class.php
<?php
class Test extends \lang\Object {}
# kiesel at vb-kiesel in ~/test [17:57:44]
$ xp -w 'newinstance("mynamespace.Test", [], "{}")->getClass();'
lang.XPClass<Test▒1>
This should output lang.XPClass<mynamespace.Test▒1>
.
Date precision
$ xp -d 'new \util\Date()'
object(util\Date)#49 (1) {
["handle":"util\Date":private]=>
object(DateTime)#50 (3) {
["date"]=>
string(26) "2019-07-03 15:18:10.393313"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
}
Internally, microseconds (.393313 in the above example) are present, the Date class however does not have accessors for these
PHP 7 support
vagrant@precise32:~/devel/xp/core$ XP_RT=7.0 xp -v
XP 6.0.0-dev { PHP 7.0.0-dev & ZE 2.8.0-dev } @ Linux precise32 3.2.0-23-generic-pae #...
Copyright (c) 2001-2014 the XP group
FileSystemCL<.../xp/core/src/main/php/>
FileSystemCL<.../xp/core/src/test/php/>
FileSystemCL<.../xp/core/src/main/resources/>
FileSystemCL<.../xp/core/src/test/resources/>
FileSystemCL<.../home/vagrant/devel/xp/core/>
vagrant@precise32:~/devel/xp/core$ XP_RT=7.0 unittest src/test/config/unittest/*.ini
# ...
OK: 5242/5449 run (207 skipped), 5242 succeeded, 0 failed
Memory used: 29637.86 kB (40745.29 kB peak)
Time taken: 2.864 seconds
Looking good for the moment (when php/php-src#848 is applied), keeping this issue for tracking while PHP 7 evolves.
See also #47 - HHVM support
PHP7 parity: Undefined methods
While in PHP 5.6, we receive a lang.Error
, in PHP7 the __call() handler itself produces an error:
$ XP_RT=5.6 xp -w '(new Object())->func()'
Uncaught exception: Exception lang.Error (Call to undefined method lang.Object::func() from scope xp.runtime.Dump)
at lang.Object::__call((0x4)'func', array[0]) [line 1 of Dump.class.php(46) : eval()'d code]
at lang.Object::func() [line 1 of Dump.class.php(46) : eval()'d code]
at <main>::eval() [line 46 of Dump.class.php]
at xp.runtime.Dump::main(array[2]) [line 281 of class-main.php]
$ XP_RT=7.0 xp -w '(new Object())->func()'
Uncaught exception: Exception lang.IndexOutOfBoundsException (Undefined index: class)
at <main>::__error(8, (0x16)'Undefined index: class', (0x3c)'C:\cygwin\home\Timm\devel\xp\core\src\main\php\lang.base.php', 30, array[5]) [line 30 of lang.base.php]
at lang.Object::__call((0x4)'func', array[0]) [line 1 of Dump.class.php(46) : eval()'d code]
at <main>::eval() [line 46 of Dump.class.php]
at xp.runtime.Dump::main(array[1]) [line 281 of class-main.php]
Add libsodium to util.Secret backings
https://wiki.php.net/rfc/libsodium
Libsodium is a modern cryptography library that offers authenticated encryption, high-speed elliptic curve cryptography, and much more. Unlike other cryptography standards (which are a potluck of cryptography primitives; i.e. WebCrypto), libsodium is comprised of carefully selected algorithms implemented by security experts to avoid side-channel vulnerabilities.
ClassParser chokes on ::class inside members
class Test extends Object {
private $classes= [self::class, parent::class];
}
Exception lang.IndexOutOfBoundsException (Uninitialized string offset: 1)
Type::$ARRAY and Type::$CALLABLE
The methods isInstance()
,cast()
, newInstance()
and isAssignableFrom()
don't work as expected.
Consistent SSL
Note: This is the reincarnation of xp-framework/xp-framework#209 /cc @kiesel
Using self-signed certificates and/or an internal CA yields problems with ext/ldap and and ext/curl:
$ xp -w '(new \peer\ldap\LDAPConnection("ldaps://ldap.1and1.org"))->connect()'
Uncaught exception: Exception peer.ConnectException (Cannot connect to ldaps://ldap.1and1.org:636)
at <main>::ldap_bind() [line 101 of LDAPConnection.class.php] ldap_bind(): Unable to bind to server: Can't contact LDAP server
(With LDAP debugging, we see the reason: TLS certificate verification: Error, self signed certificate in certificate chain
)
$ xp -w '(new \peer\http\HttpConnection("https://bitbucket.1and1.org"))->get()'
Uncaught exception: Exception io.IOException (60: SSL certificate problem: self signed certificate in certificate chain)
at peer.http.CurlHttpTransport::send(peer.http.HttpRequest{}, 60, 2) [line 123 of HttpConnection.class.php]
(Here, it's obvious)
The problem is that these don't use the Windows certificate store which contains the certificate, while ext/openssl does since PHP 5.6.0 - see the Changelog:
Fallback to Windows CA cert store for peer verification if no openssl.cafile ini directive or "cafile" SSL context option specified in Windows.
Source: http://php.net/ChangeLog-5.php#5.6.0 and the code
Endless recursion for overlay module use-case
I wanted to create an overlay module - that is, a module registering its class loader in front of the class path in order to overlay core classes:
module.xp
<?php namespace unittest\web;
use lang\ClassLoader;
module xp-framework/webtest {
public function initialize() {
ClassLoader::registerLoader($this->classLoader(), true);
}
}
This causes an endless recursion.
Warnings in Type::forName()
The following surface from time to time:
<main>::substr_compare()
[line 148 of Type.class.php] substr_compare(): The start position cannot exceed initial string length<main>::substr_compare()
[line 150 of Type.class.php] substr_compare(): The start position cannot exceed initial string length<main>::substr_compare()
[line 152 of Type.class.php] substr_compare(): The start position cannot exceed initial string length
FunctionType doesn't load classes
$ xp -w '(new \lang\FunctionType([\lang\Type::$VAR], \lang\Primitive::$VOID))->cast("unittest.assert.Value::new")'
Uncaught exception: Exception lang.reflect.TargetInvocationException (xp\runtime\Dump::main)
at lang.reflect.Method::invoke(NULL, array[1]) [line 248 of class-main.php]
Caused by Exception lang.ClassNotFoundException (Class "php.Value" could not be found) {
FileSystemCL<...\xp\assert\src\main\php\>
FileSystemCL<...\xp\assert\src\test\php\>
FileSystemCL<...\xp\core\src\main\php\>
FileSystemCL<...\xp\core\src\test\php\>
FileSystemCL<...\xp\core\src\main\resources\>
FileSystemCL<...\xp\core\src\test\resources\>
FileSystemCL<...\home\Timm\devel\xp\assert\>
}
at lang.ClassLoader::loadClass0((0x9)'php.Value') [line 473 of ClassLoader.class.php]
at lang.ClassLoader::loadClass((0x9)'php.Value') [line 734 of XPClass.class.php]
at lang.XPClass::forName((0x9)'php.Value') [line 149 of Type.class.php]
at lang.Type::forName((0x9)'php.Value') [line 194 of FunctionType.class.php]
at lang.FunctionType::verifiedMethod((0x15)'unittest.assert.Value', (0x3)'new', php.Closure{}, 1) [line 160 of FunctionType.class.php]
at lang.FunctionType::verified((0x1a)'unittest.assert.Value::new', php.Closure{}) [line 258 of FunctionType.class.php]
at lang.FunctionType::cast((0x1a)'unittest.assert.Value::new') [line 1 of Dump.class.php(45) : eval()'d code]
at <main>::eval() [line 45 of Dump.class.php]
at xp.runtime.Dump::main(array[2]) [line 0 of StackTraceElement.class.php]
at php.ReflectionMethod::invokeArgs(NULL, array[1]) [line 93 of Method.class.php]
ClassParser and "use .. as .."
<?php namespace test;
use lang\Object as Base;
#[@value(new Base())]
class Test extends Base {
}
Fetching annotation's value leads to an exception being raised.
Typed properties
See https://wiki.php.net/rfc/typed_properties_v2 - since PHP 7.4
class User {
public int $id;
public string $name;
public function __construct(int $id, string $name) {
$this->id = $id;
$this->name = $name;
}
}
Union types support
Using PHP 8 union types currently yields an error when using reflection
Call to undefined method ReflectionUnionType::getName()
Part of PHP 8 compatibility - see #211
TestSuite cannot handle @expect annotation with empty 'withMessage' attribute
Given a test like:
#[@test, @ignore, @expect(class= 'lang.Throwable', withMessage= '')]
public function expect_some_exception() {
// ...
}
This leads to:
$ unittest src/test/php
[............................................................NNNUncaught exception: Exception lang.reflect.TargetInvocationException (xp.unittest.Runner::main)
at lang.reflect.Method::invoke(NULL, array[1]) [line 350 of class-main.php]
Caused by Exception lang.IndexOutOfBoundsException (Uninitialized string offset: 0)
at <main>::__error(8, (0x1e)'Uninitialized string offset: 0', (0x70)'/home/idev/dev/xp.private/trunk/xp5/libs/ibus/vendor/xp-framewor', 248, array[6]) [line 248 of TestSuite.class.php]
at unittest.TestSuite::runInternal(org.oneandone.ibus.command.MessageConsumerCommandTest{}, unittest.TestResult{}) [line 565 of TestSuite.class.php]
at unittest.TestSuite::run() [line 369 of Runner.class.php]
at xp.unittest.Runner::run(array[1]) [line 380 of Runner.class.php]
at xp.unittest.Runner::main(array[1]) [line 0 of StackTraceElement.class.php]
at ReflectionMethod::invokeArgs(NULL, array[1]) [line 90 of Method.class.php]
HHVM support
After xp-runners is now basically looking good, this issue gathers all tasks necessary to support HHVM.
HHVM incompatibilities & bugs
Various bugs in HHVM need to be addressed, workarounds found and PHP compatibility retained at the same time. Travis CI will be a great help here:)
Hack language
HHVM brings Hack language. It features stuff PHP will or might see at some day in the future, e.g. return types, annotations or function types; and others it will probably not, like generics, type aliases, XHP, to name a few. An overview of Hack language features can be found here
See also #36 - PHP 7 support
Generics and members
#[@generic(self= 'T')]
class Test {
/** @type T[] */
public $list;
}
This does not work as expected /cc @pdietz
HHVM 3.26 issues
With HHVM 3.25:
friebe@vm-gamify:~/devel/core$ ./php -v
HipHop VM 3.25.1 (rel)
Compiler: 1521755894_584615862
Repo schema: 118057063544eca576fc14c2f4181c8005acec43
friebe@vm-gamify:~/devel/core$ XP_RT=./php xp -cp test.xar xp.unittest.Runner \
src/test/config/unittest/core.ini
# ...
♥: 2152/2219 run (67 skipped), 2152 succeeded, 0 failed
Memory used: 12288.00 kB (12288.00 kB peak)
Time taken: 27.136 seconds
With HHVM 3.26
friebe@vm-gamify:~/devel/core$ ./php -v
HipHop VM 3.26.3 (rel)
Compiler: 1527196551_665484780
Repo schema: 5ed0d6795a50e36e6652cd6d0038d702c90ab158
friebe@vm-gamify:~/devel/core$ XP_RT=./php xp -cp test.xar xp.unittest.Runner \
src/test/config/unittest/core.ini
ExternCompiler Fatal: Failure("int_of_string")
Fatal error: Uncaught Error: Failure("int_of_string") in /.../StringOfTest.class.php:-1
Also, another error spread out over a bunch of classes:
$ XP_RT=./php xp -w 'return new class implements \lang\Value {
function toString() { return "X"; }
function hashCode() { return "X"; }
function compareTo($value) { return 1; }
}'
X
$ XP_RT=./php xp -w 'use lang\Value; return new class implements Value {
function toString() { return "X"; }
function hashCode() { return "X"; }
function compareTo($value) { return 1; }
}'
Uncaught error: Fatal error (Undefined interface: Value)
at <source> [line 1 of .../Code.class.php(124)... : eval()'d code]
PHP 7.4 modifiers compatiblity
When running the test suite with a current PHP 7.4 build, before the tests even begin, the program is terminated with Uncaught exception: Exception lang.ClassFormatException (Cannot access public abstract field net.xp_framework.unittest.annotations.ClassMemberParsingTest::$value in net.xp_framework.unittest.annotations.ClassMemberParsingTest, line 46). This is due to the modifiers bitfield having been changed, ReflectionProperty::IS_PUBLIC
is now 1 instead of 256, which was its previous value. XP Framework defines global constants for easier access, and hardcodes its values (which it shouldn't have done in the first place - however, their values haven't changed since PHP 5.0.0 (!)).
Void return type breaks newinstance()
abstract class Base {
public abstract function fixture(): void;
}
newinstance(Base::class, [], [
'fixture' => function($arg): void { }
]);
Uncaught error: Compile error (Declaration of Base▒1::fixture() must be compatible with Base::fixture(): void)
Since PHP 7.1 - see https://wiki.php.net/rfc/void_return_type
Ambiguity in function types
Declaring a function type
/**
* Fixture
*
* @param function(var): int $mapToInt
* @return void
*/
Declaring an array of function types
/**
* Fixture
*
* @param function(var): int[] $mapToInt
* @return void
*/
🔴 Ambiguous - Does this declare a function that returns an array of int or is this an array of functions returning int? - currently, resolves to the first!
Warning in String::endsWith
$ xp -w '[(new \lang\types\String("Hello"))->endsWith(""), xp::$errors]'
[false, [
C:\cygwin\home\Timm\devel\xp\core\src\main\php\lang\types\String.class.php => [
275 => [
substr_compare(): The length must be greater than zero => [
class => null
method => "substr_compare"
cnt => 1
]
]
]
]]
Scalar type hints break newinstance()
abstract class Base {
public abstract function fixture(string $arg);
}
newinstance(Base::class, [], [
'fixture' => function(string $arg) { return 'Hello'; }
]);
Uncaught error: Compile error (Declaration of Base▒1::fixture($arg) must be compatible with Base::fixture(string $arg))
HHVM builds broken
See https://travis-ci.org/xp-framework/core/jobs/426839764:
Exception lang.Error (Class undefined: IllegalStateException)
at <native>::Error(0, (0x26)'Class undefined: IllegalStateException')
[line 132 of ConsoleTest.class.php]
The code here is:
try {
Console::write(new class() implements Value {
public function toString() { throw new IllegalStateException('Cannot render string'); }
public function hashCode() { return get_class($this); }
public function compareTo($value) { return 1; }
});
$this->fail('Expected exception not thrown', null, 'lang.IllegalStateException');
} catch (IllegalStateException $expected) {
$this->assertEquals('', $this->streams[1]->getBytes());
}
Line 132 is the one with throw new IllegalStateException on it.
Problems caused by facebook/hhvm#8319
uses() does not create short named class aliases
The following snippet should actually work:
# kiesel at vb-kiesel in ~/dev/xp6/core on git:master o [17:31:33]
$ USE_XP=. xp -w 'uses("util.Date"); return new Date();'
PHP Fatal error: Class 'Date' not found in /home/idev/dev/xp6/core/src/main/php/xp/runtime/Dump.class.php(45) : eval()'d code on line 1
PHP Stack trace:
PHP 1. {main}() /home/idev/bin/class-main.php:0
PHP 2. lang\reflect\Method->invoke() /home/idev/bin/class-main.php:259
PHP 3. ReflectionMethod->invokeArgs() /home/idev/dev/xp6/core/src/main/php/lang/reflect/Method.class.php:93
PHP 4. xp\runtime\Dump::main() /home/idev/dev/xp6/core/src/main/php/lang/reflect/Method.class.php:93
PHP 5. eval() /home/idev/dev/xp6/core/src/main/php/xp/runtime/Dump.class.php:45
Exception lang.Error (Fatal error)
at <main>::xp\{closure}() [line 1 of Dump.class.php(45) : eval()'d code] Class 'Date' not found
at <main>::xp\{closure}() [line 0 of StackTraceElement.class.php]
XPClass::newInstance() declaration warning
[line 56 of XPClass.class.php] Declaration of lang\XPClass::newInstance(...$args) should be compatible with lang\Type::newInstance($value = NULL)
Make lang.Object -> lang.Value migration easier
Scenario
A typical migration to XP9 will include replacing all extends \lang\Object
with one of the two following:
- Nothing - in which case you're done.
- With
implements \lang\Value
- and then implementinghashCode()
,compareTo()
andtoString()
.
The key point here is that implementing hashCode()
and compareTo()
can prove to be tedious, especially if I only want the added benefits of a nice toString()
output.
Example
This is a diff in the xp-framework/webservices library where I really don't care much about comparing, but want the toString()
method.
index 087a1a6..f187f51 100644
--- a/src/main/php/webservices/rest/RestResponse.class.php
+++ b/src/main/php/webservices/rest/RestResponse.class.php
@@ -9,7 +9,7 @@ use peer\http\HttpResponse;
*
* @test xp://net.xp_framework.unittest.webservices.rest.RestResponseTest
*/
-class RestResponse {
+class RestResponse implements \lang\Value {
protected $response= null;
protected $reader= null;
protected $input= null;
@@ -213,4 +213,23 @@ class RestResponse {
public function toString() {
return nameof($this).'<'.$this->response->message().'>@(->'.$this->response->toString().')';
}
+
+ /**
+ * Creates a hashcode
+ *
+ * @return string
+ */
+ public function hashCode() {
+ return uniqid();
+ }
+
+ /**
+ * Comparison
+ *
+ * @param var $value
+ * @return int
+ */
+ public function compareTo($value) {
+ return $value === $this ? 0 : 1;
+ }
}
Suggestions
Either add a \lang\Stringable
interface and support that in the relevant places or add a trait \lang\Comparison
which implements hashCode()
and compareTo()
generically. Alternatively, simply check for toString()
instead of testing with instanceof
, kind of the magic PHP way...
TypeUnion literal bug
$ xp -w '\lang\Type::forName("string|int")->literal()'
Uncaught exception: Error (Call to a member function literal() on null)
at <source> [line 65 of .\src\main\php\lang\TypeUnion.class.php]
# ...
Restore HHVM support
$ XP_RT=hhvm xp -v
Fatal error: Uncaught exception 'Exception' with message 'This version of the XP Framework
requires PHP 7.0.0+, have PHP 5.6.99-hhvm'
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.