Language basics¶
Note
Coding Java from PHP is relatively similar to an equivalent pure Java code. To avoid confusion while developing you must keep aware that:
- Java supports overloading for methods (and constructors).
- PHP have the multipurpose array for everything, Java does not. See here to learn more.
- DateTime and timezones are handled differenlty, see here to learn more.
- Java supports inner classes. See here
And remember
- While array and scalar types (int, string, bool, float) are automatically casted,
testing on
null
andbooleans
requires the use of$ba->isNull()
and$ba->isTrue()
methods. See here to learn more. - PHP use the
::
for static method calls and constants where Java does not.
.
soluble-japha brings solutions to those problems, but primary reflexes might not work (i.e. you try to call a static java method through the bridge with '::' instead of the regular '->'...)
Object instantiation¶
Whenever you want to work with a Java Object you must instantiate it through
the $ba->java('[JAVA_FQCN]', $arg1=null, $arg2=null, ...)
.
Simple constructor¶
<?php
$ba = new \Soluble\Japha\Bridge\Adapter([
'driver' => 'Pjb62',
'servlet_address' => 'localhost:8083/servlet.phpjavabridge'
]);
$string = $ba->java('java.lang.String', 'Hello world');
$hash = $ba->java('java.util.HashMap', ['key1' => $string, 'key2' => 'hello']);
Tip
The [JAVA FQCN] is the fully qualified java class name (case-sensitive) optionally
followed by a list of arguments (variadic notation: BridgeAdapter::java(string $javaClass, ...$args)
).*
Overloaded constructor¶
In case of multiple constructor signatures (PHP does not have constructor overloading), look at :
<?php
$mathContext = $ba->java('java.math.MathContext', $precision=2);
$bigint = $ba->java('java.math.BigInteger', 123456);
$bigdec = $ba->java('java.math.BigDecimal', $bigint, $scale=2, $mathContext);
Tip
Refer to the BigDecimal constructor to learn how it has been selected from the provided arguments.
Methods¶
After creating a java object with $ba->java('[JAVA_FQCN]', $arg1=null, $arg2=null, ...)
you can call
any public methods on it. Keep it mind that Java supports method overloading,
so before calling a method, ensures parameters will match the desired method signature.
For example the java.lang.String object exposes
two methods for indexOf()
<?php
$javaString = $ba->java('java.lang.String', 'A key is a key!');
$index = $javaString->indexOf('key');
// Will print 2, the selected method is `java.lang.String#indexOf(String str)`
$index = $javaString->indexOf('key', $fromIndex=8);
// Will print 11, the selected method is `java.lang.String#indexOf(String, $fromIndex)`
Classes¶
Use the $ba->javaClass('[JAVA FQCN]', $arg1=null, ...)
method instead of
$ba->java()
...
Take a look to the following example with java.lang.System class.
<?php
$system = $ba->javaClass('java.lang.System');
echo $system->getProperties()->get('java.vm_name');
Static methods¶
Static methods are called like regular php methods (no ::
).
<?php
$calendar = $ba->javaClass('java.util.Calendar')->getInstance();
Tip
Note the use of $ba->javaClass(...)
instead of $ba->java(...)
to refer to
the java class and call the static method on it. Remember to use it whenever
you face a factory, singleton or a generic static method.
Constants¶
Constants on java classes are called like regular properties (no ::
).
<?php
// $ba = new BridgeAdapter(...);
$tzClass = $ba->javaClass('java.util.TimeZone');
echo $tz->getDisplayName(false, $tzClass->SHORT);
Iterables¶
Warning
Iterations have a cost on performance, and looping over large sets is highly discouraged. See how you can improve speed with the values() method.
You can use standard foreach
, while
, for
,... to loop over Java iterable objects (Map, Collection, List...).
<?php
// $ba = new BridgeAdapter(...);
$properties = $ba->javaClass('java.lang.System')->getProperties();
foreach ($properties as $key => $value) {
echo "$key: $value\n";
}
ArrayAccess¶
Interfaces\JavaObject
implements ArrayAccess
which allows to write
maps, arrays... in a more convenient way. An example with HashMap
:
<?php
// $ba = new BridgeAdapter(...);
$hashMap = $ba->javaClass('java.util.HashMap');
$hashMap['test'] = 'Cool'; // equivalent to `$hashMap->put('test', 'Cool');`
if (isset($hashMap['test'])) {
unset($hashMap['test']);
}
Inner classes¶
Java supports inner classes (classes as a class property).
To explicitly refer to an inner class, the FQCN
separator must be a $
sign instead
of the regular .
.
The following example makes use of the Calendar.Builder class:
<?php
// $ba = new BridgeAdapter(...);
// NOTICE THE DOLLAR SIGN in 'Calendar$Builder'
$builder = $ba->java('java.util.Calendar$Builder');
echo $ba->getClassName($builder); // will print 'java.util.Calendar$Builder'
$calendar = $builder->setCalendarType('gregory')->build();
echo $ba->getClassName($calendar); // will print 'java.util.GregorianCalendar'
Warning
As PHP will interpret the $
as a variable, be sure to use
single-quotes to hold the class name.
Datatypes¶
Scalar types¶
The PHP scalar types: string
, int
, float
and boolean
can be sent
as parameters to Java methods or constructors transparently:
<?php
$price = 12.99;
$quantity = $ba->java('java.lang.Integer', 10);
$jstring = $ba->java('java.lang.String', 'Hello world');
Tip
Be aware that Java often use object versions of scalars, like
java.lang.String
, java.lang.Integer
, java.lang.Boolean
...
In those cases, remember they generally provides methods to
retrieve the scalar value. For example:
<?php
$quantity = $ba->java('java.lang.Integer', 10);
$total = $quantity->intValue() * 12.99;
echo sprintf('Total id %.2f', $total); // -> 1299.00
Array types¶
The PHP multi-purpose array has not equivalent in Java and you'll often use Java objects like Map, HashMap, Collection, List, Vector... instead.
<?php
$array = ['name' => 'John Doe', 'age' => 26];
$hashMap = $ba->java('java.util.HashMap', $array);
While you can generally send the parameters as a standard php array, to
get an array back you can use the fast values()
method:
<?php
// with HashMap
$input_array = ['name' => 'John Doe', 'age' => 26];
$hashMap = $ba->java('java.util.HashMap', $input_array);
$output_array = $ba->values($hashMap);
// $input_array === $output_array
// With ArrayList
$arrayList = $ba->java('java.util.ArrayList');
$arrayList->add('Hello');
$arrayList->add('World');
$array = $ba->values($arrayList->toArray());
// $array == ['Hello', 'World'];
or iterate the object (ok for small sets).
Testing null and booleans¶
Warning
Testing null and boolean:
Due to internal proxying between java and php objects, 'null', 'false' and 'true' values must be tested through the bridge object. Otherwise the test is made the php proxied object and not its value.
<?php
// $ba = new BridgeAdapter(...);
$javaBoolean = $ba->java('java.lang.Boolean', true);
if ($ba->isTrue($javaBoolean)) {
echo "Yes, it is.";
}
$javaBoolean = $ba->java('java.lang.Boolean', false);
if (!$ba->isTrue($javaBoolean)) {
echo "Yes, it is not.";
}
if (!$ba->isNull($rs)) {
$rs->close();
}
Working with dates¶
Warning
Dates are not (yet) automatically casted between Java and PHP. Keep in mind that
- Internally the JVM works with milliseconds, PHP with to microseconds (7.1 introduced milli).
- Timezones might differs between runtimes. Check your configuration.
As an example, the java.util.Date allows creation of dates based on a timestamp expressed in milliseconds :
<?php
// $ba = new BridgeAdapter(...);
$phpDate = \DateTime::createFromFormat('Y-m-d', '2016-12-21');
$milli = $phpDate->format('U') * 1000; // Internally the JVM handles milliseconds
// In order to create a new Java date,
// php dates must be converted accordingly.
// The 'U' allows formatting the date as
// microseconds since epoch time, just multiply
// by 1000 to get milliseconds.
// Alternatively you can use
// $milli = strtotime('2016-12-21') * 1000;
$javaDate = $ba->java('java.util.Date', $milli);
$simpleDateFormat= $ba->java("java.text.SimpleDateFormat", 'yyyy-MM-dd');
echo $simpleDateFormat->format($javaDate);
// Will print: "2016-12-21"
Alternatively you can use the java.text.SimpleDateFormatter object to parse the date string without the php conversion.
<?php
// $ba = new BridgeAdapter(...);
$date = '2016-12-21';
$simpleDateFormat = $ba->java("java.text.SimpleDateFormat", 'yyyy-MM-dd');
$javaDate = $simpleDateFormat->parse($date); // This is a Java date
echo $simpleDateFormat->format($javaDate);
// Will print: "2016-12-21"
Timezones¶
Timezones might differ from PHP and the JVM runtimes. In that case, dates between PHP and Java are not guaranteed to be the same (think of 2016-12-31 23:00:00 in London and Paris)
In most cases those differences can be easily fixed by ensuring both the JVM and PHP configurations use the same timezone.
Another option is to pass the current timezone in the formatter :
<?php
$pattern = "yyyy-MM-dd HH:mm";
$formatter = $ba->java("java.text.SimpleDateFormat", $pattern);
$tz = $ba->javaClass('java.util.TimeZone')->getTimezone("Europe/Paris");
$formatter->setTimeZone($tz);
Resources¶
PHP resources like pointer to a file or a network socket cannot be exchanged between runtimes.
IO streams¶
Warning
For performance, operations on resources (like iterating over a file) is highly discouraged. They should be made on their own environment.
As an example
<?php
$bufferedReader = $ba->java('java.io.BufferedReader',
$ba->java('java.io.FileReader', __FILE__)
);