chippyash/Type
Quality Assurance
, _{(*1)}
The above badges represent the current development branch. As a rule, I don't push
to GitHub unless tests, coverage and usability are acceptable. This may not be
true for short periods of time; on holiday, need code for some other downstream
project etc. If you need stable code, use a tagged version. Read 'Further Documentation'
and 'Installation'., _{(*2)}
Please note that developer support for PHP5.3 was withdrawn at version 4.0.0 of this library.
It may be that the code will continue to run for you at later versions, but you must
ascertain that for yourself. If you need support for PHP 5.3, please use a version
>=3,<4
, _{(*3)}
Also note that developer support for PHP5.4 & 5.5 was withdrawn at version 5.0.0 of this library.
It may be that the code will continue to run for you at later versions, but you must
ascertain that for yourself. If you need support for PHP 5.4 or 5.5, please use a version
>=4,<5
, _{(*4)}
GMP support is tested on the Travis-ci build servers for PHP V5.6 as that is the only
version that stable gmp support is available for., _{(*5)}
See the Test Contract in the docs directory., _{(*6)}
What?
Provides strong type implementations of base PHP types. Adds some 'missing'
numeric types., _{(*7)}
Types supported
- BoolType
- DigitType
- FloatType
- ComplexType
- IntType
- NaturalIntType
- WholeIntType
- RationalType
- StringType
The library is released under the GNU GPL V3 or later license, _{(*8)}
Why?
One of the joys of PHP is its loose typing, but there are situations, particularly
in large or complex systems where you want to guarantee that method parameters are
what you want them to be. PHP's type hinting extends to a few basic native types
such as arrays and hard typing to class names. For the rest you end up having to
put a lot of boiler plate in your methods just to ensure that when you expect a
float for instance, you get one (or use hhvm ;-) ). This library addresses the
issue for some basic PHP types plus some extensions for what could be considered
'missing' types., _{(*9)}
The most common use case for this library is as a strong type hinter for your public methods:, _{(*10)}
public function myFunc(StringType $str, IntType $ival);
Bingo: your function expects a StringType and and an IntType and nothing else!, _{(*11)}
The primary purpose of strong typing in this context is to guard your public
methods against unwarranted side effects. Unwrap the native type at the point
of use., _{(*12)}
The secondary use case is for when you want to start using some missing types fromPHP,
in particular Rational (fractions) and Complex numeric types. I've built a reasonably
comprehensive Mathematical Matrix library based on the numeric types from this library., _{(*13)}
PHP 7 warning
PHP 7 introduces type hinting for native types
but the problem is that you are going to get an automatic conversion or caste. Not what I'd
expect. In the meantime, use this StongType library to harden your application., _{(*14)}
That said, once you get into the swing of using the basic types, you'll find them most amenable to being passed
around and used interchangeably with PHP native types, primarily because they support a __toString() method and
__invoke() which proxies to the get() method., _{(*15)}
public function myFunc(StringType $str, IntType $ival)
{
echo $str;
$foo = "The amount is {$ival}";
$n = 2 * $ival();
}
When
The current library covers basic data types plus some extensions., _{(*16)}
If you want more, either suggest it, or better still, fork it and provide a pull request., _{(*17)}
See The Matrix Packages for other packages from Chippyash, _{(*18)}
How
Coding Basics
Very simple way
This is how we use it in everyday work to ensure that our calls to some function
is conformant:, _{(*19)}
function foo(FloatType $foo) {...}
$myFoo = foo(new FloatType(1);
NB. The integer 1
is going to get converted into a float 1.0
but that is ok
because our method foo()
expects a FloatType and with PHPs current type hinting
can enforce it., _{(*20)}
For those that have the stamina
Create a type via the Type Factory:, _{(*21)}
use Chippyash\Type\TypeFactory;
$str = TypeFactory::create('string','foo');
//or
$str = TypeFactory::createString('foo');
$int = TypeFactory::createInt(2);
//or
$int = Typefactory::create('int', 2);
//some types can take two parameters
$rat = TypeFactory::create('rational', 2, 3);
etc, etc, _{(*22)}
Supported type tags are:, _{(*23)}
- bool (or boolean)
- digit
- float (or double)
- complex
- int (or integer)
- natural
- whole
- rational
- string
Create one directly:, _{(*24)}
use Chippyash\Type\Number\Complex\ComplexType;
use Chippyash\Type\Number\Rational\Rationaltype;
use Chippyash\Type\String\DigitType;
use Chippyash\Type\String\StringType;
use Chippyash\Type\Number\FloatType;
use Chippyash\Type\Number\IntType;
$c = new ComplexType(new RationalType(new IntType(-2), new IntType(1)), new RationalType(new IntType(3), new IntType(4));
$d = new DigitType(34);
$s = new StringType('foo');
$d2 = new DigitType('34foo'); // == '34'
$r = new RationalType(new IntType(1), new IntType(2));
etc, etc, _{(*25)}
Create a complex type via the Complex Type Factory (n.b. the Type Factory uses
this), _{(*26)}
use Chippyash\Type\Number\Complex\ComplexTypeFactory;
$c = ComplexTypeFactory::create('13-2.67i');
//same as
$c = ComplexTypeFactory::fromString('13-2.67i');
$c = ComplexTypeFactory::create(2.4, new IntType(-6));
$c = ComplexTypeFactory::create(2, -61.78);
$c = ComplexTypeFactory::create(new FloatType(2), -61.78);
//i.e. any pair of numeric, intType, FloatType or RationalType values can be used to create
//a complex type via the factory
Create a rational type via the Rational Type Factory (n.b. the Type Factory uses
this, but using it directly may give you finer grain control in some circumstances.), _{(*27)}
use Chippyash\Type\Number\Rational\RationalTypeFactory;
$r = RationalTypeFactory::create(M_1_PI); //results in 25510582/80143857
$r = RationalTypeFactory::fromFloat(M_1_PI); //ditto
$r = RationalTypeFactory::fromFloat(M_1_PI, 1e-5); //results in 113/355
$r = RationalTypeFactory::fromFloat(M_1_PI, 1e-17); //results in 78256779/245850922
$r = RationalTypeFactory::create('2/3');
//same as
$r = RationalTypeFactory::fromString('2/3');
RationalTypeFactory::fromFloat obeys the current setting of RationalTypeFactory::$defaultTolerance. The default
value is 1e-15. You can change this by calling RationalTypeFactory::setDefaultFromFloatTolerance() at the beginning
of your program., _{(*28)}
All types support the TypeInterface:, _{(*29)}
- get() - return the value as a PHP native type (if possible)
- set($value) - set the value
- __toString() - Magic toString method. Return value as a string
- __invoke() - Proxy to get(), allows you to write $c() instead of $c->get()
Numeric types, that is IntType, WholeIntType, NaturalIntType, FloatType, RationalType
and ComplexType support the NumericTypeInterface which defines the methods, _{(*30)}
- negate(): negate the number - NB Negation is will throw a \BadMethodCallException for WholeInt and NaturalInt types as they cannot be negative
- asComplex(): returns a complex real representation of the number (e.g. 2+0i). For
complex types, simply clones the existing object.
- asRational(): returns rational representation of the number. For rational types, simply clones the existing object.
- asIntType(): returns number caste as IntType. For IntType, simply clones the existing objeoct.
- asFloatType(): returns number caste as FloatType. For FloatType, simply clones the existing objeoct.
- abs(): return the absolute value of the number
- sign(): return sign of number: -1 == negative, 0 == zero, 1 == positive
IntTypes support two additional methods:, _{(*31)}
- factors(): array: returns a sorted array of factors of the number
- primeFactors(): array: returns [primeFactor => exponent,...] i.e the primeFactor => number of times it occurs
Additionally, the RationalType supports the RationalTypeInterface:, _{(*32)}
- numerator() - return the integer value numerator
- denominator() - return the integer value denominator
NB, AbstractRationalType amends the set() method to proxy to setFromTypes(), i.e. calling RationalType::set()
requires the same parameters as setFromTypes(), _{(*33)}
Additionally the ComplexType supports the ComplexTypeInterface:, _{(*34)}
- r() - return the real part as a RationalType
- i() - return the imaginary part as a RationalType
- isZero() - Is this number equal to zero?
- isReal() - Is this number a real number? i.e. is it in form n+0i
- isGuassian() - Is this number Gaussian, i.e r & i are both equivalent to integers
- conjugate() - Return conjugate of this number
- modulus() - Return the modulus, also known as absolute value or magnitude of this number
- theta() - Return the angle (sometimes known as the argument) of the number when expressed in polar notation
- radius() - Return the radius (sometimes known as Rho) of the number when expressed in polar notation
- asPolar() - Returns complex number expressed in polar form i.e. an array [radius, theta]
- polarQuadrant() - Returns the polar quadrant for the complex number
- polarString() - Return complex number expressed as a string in polar form i.e. r(cosĪø + iā
sinĪø)
NB, ComplexType amends the set() method to proxy to SetFromTypes, i.e. calling ComplexType::set()
requires the same parameters as setFromTypes()., _{(*35)}
There is no PHP native equivalent for a ComplexType, therefore the get() method proxies to the
__toString() method and returns something in the form [-]a(+|-)bi e.g. '-2+3.6i' except where
The ComplexType->isReal() in which case get() will return a float or an int. If you need to disambiguate
then use ComplexType::toFloat() which will throw an exception if the number is not real., _{(*36)}
Polar form complex numbers are supported by the polar methods in ComplexType and also by the
ComplexTypeFactory::fromPolar(RationalType $radius, RationalType $theta) method., _{(*37)}
Support for GMP extension - V2 onwards only
The library automatically recognises the availability of the gmp extension and
will use it for int, rational and complex types., _{(*38)}
There is no gmp support for WholeIntType, NaturalIntType or FloatType., _{(*39)}
- WholeIntType and NaturalIntType creation via the TypeFactory will return GMPIntType.
- The validation for whole and natural numbers is ignored - they are treated as integers
- FloatType creation via the TypeFactory will return a GMPRationalType.
You can force the library to use PHP native types by calling, _{(*40)}
use Chippyash\Type\RequiredType;
RequiredType::getInstance()->set(RequiredType::TYPE_NATIVE);
at the start of your code. This will in turn call the setNumberType methods on the
other factories, so you don't need to do that, _{(*41)}
If you want to get the gmp typed value of a number you can call its gmp() method., _{(*42)}
//assuming we are running under gmp
$i = TypeFactory::create('int', 2); //returns GMPIntType
$i = TypeFactory::create('whole', -1); //returns GMPIntType
$i = TypeFactory::create('natural', 0); //returns GMPIntType
$gmp = $i->gmp(); //returns resource or GMP object depending on PHP version
$r = TypeFactory::create('rational', 2, 3); //returns GMPRationalType
$r = TypeFactory::create('float', 2/3); //returns GMPRationalType
$gmp = $i->gmp(); //returns resource or GMP object depending on PHP version
$r = TypeFactory::create('rational', 2, 3); //returns GMPRationalType
$gmp = $r->gmp(); //returns array of gmp types, [numerator, denominator]
$c = TypeFactory::create('complex', '2+3i'); //returns GMPComplexType
$gmp = $c->gmp(); //returns array of gmp types, [[num,den],[num,den]] i.e. [r,i]
All GMP types support the GMPInterface, so in addition to having the gmp() method,
they will also have:, _{(*43)}
- public function asGMPIntType() Return number as GMPIntType number. Will return floor(n/d) for rational types
- public function asGMPComplex() : Return the number as a GMPComplex number i.e. n+0i
- public function asGMPRational(): Return number as GMPRational number.
Trying to keep track of what types you are actually instantiating is made much easier if
you use the type factories, as they know which types to create. Therefore if
you want your code to be runnable as PHP native or GMP, use the factories to
create your numeric types., _{(*44)}
Further documentation
You can find the API documentation here, _{(*45)}
Test Contract in the docs directory., _{(*46)}
Check out ZF4 Packages for more packages, _{(*47)}
UML
, _{(*48)}
Changing the library
- fork it
- write the test
- amend it
- do a pull request
Found a bug you can't figure out?, _{(*49)}
- fork it
- write the test
- do a pull request
NB. Make sure you rebase to HEAD before your pull request, _{(*50)}
Or - raise an issue ticket., _{(*51)}
Where?
The library is hosted at Github. It is
available at Packagist.org, _{(*52)}
Installation
Install Composer, _{(*53)}
For production
Use V5 unless you have a strong reason not to., _{(*54)}
<, _{(*55)}
pre>
"chippyash/strong-type": ">=5.0.0,<6"
, _{(*56)}
V5 branch is the default, no further development of ealier versions will take place., _{(*57)}
For development
Clone this repo, and then run Composer in local repo root to pull in dependencies, _{(*58)}
, _{(*59)}
git clone git@github.com:chippyash/Strong-Type.git StrongType
cd StrongType
composer update
To run the tests:, _{(*60)}
, _{(*61)}
cd StrongType
vendor/bin/phpunit -c test/phpunit.xml test/
License
This software library is released under the BSD 3 Clause license, _{(*62)}
This software library is Copyright (c) 2014-2018, Ashley Kitson, UK, _{(*63)}
This software library contains code items that are:, _{(*64)}
- Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
- released under the New BSD License
In particular the code items are:, _{(*65)}
- elements of Chippyash\Type\String\DigitType
- all of Chippyash\Zend\ErrorHandler
None of the contained code items breaks the overriding license, or vice versa, as
far as I can tell. So as long as you stick to BSD license(or comaptible) then you are
safe. If at all unsure, please seek appropriate advice., _{(*66)}
If the original copyright owners of the included code items object to this inclusion,
please contact the author., _{(*67)}
This library is supported by
who provide their IDEs to Open Source developers., _{(*68)}
History
V0... pre releases, _{(*69)}
V1.0.0 Original release, _{(*70)}
V1.0.1 Remove requirement for zendfilter package to reduce dependency footprint, _{(*71)}
Add NumericTypeInterface to support other usages of library
V1.0.2 Add conjugate method to complex type, _{(*72)}
rebase wholeInt and naturalInt type on intType
V1.0.3 Add modulus method to complex type, _{(*73)}
V1.0.4 Fix RationalTypefactory::fromFloat not recognising zero, _{(*74)}
V1.0.5 Add negate() method to numeric types, _{(*75)}
V1.0.6 Add isReal() method for complex numbers, _{(*76)}
add toFloat() method for complex numbers if number isReal()
V1.0.7 Add toComplex() method for numeric types, _{(*77)}
V1.0.8 Add abs() method for numeric types, _{(*78)}
V1.0.9 Add asRational, asFloatType and asIntType methods for numeric types. Rename toComplex -> asComplex method, _{(*79)}
V1.0.10 Refactor Typefactory to use as... methods, _{(*80)}
V1.0.11 Ensure isolation of type parts in as... methods, _{(*81)}
V1.1.0 Add Polar form complex number support, _{(*82)}
move interfaces to separate folder
V1.1.1 Remove hard coded tolerance levels to fromFloat. Use default 1e-15 instead., _{(*83)}
V1.1.2 Ensure clone clones inner objects correctly, _{(*84)}
V1.1.3 Refactor in preparation for supporting GMP types, _{(*85)}
V2.0.0 Add GMP support, _{(*86)}
V2.0.1 Additional gmp type checking, _{(*87)}
V2.0.2 update Zend dependencies, _{(*88)}
V2.0.3 fix tests breaking if GMP not installed - will skip properly, _{(*89)}
V2.0.4 add homepage to composer.json definition, _{(*90)}
V2.0.5 small amend to fix complex creation problem for calculator, _{(*91)}
V2.0.6 update phpunit to ~V4.3.0, _{(*92)}
V2.0.7 add test contract, _{(*93)}
V2.0.8 when GMP support enabled:, _{(*94)}
- WholeIntType and NaturalIntType creation via the TypeFactory will return GMPIntType.
- FloatType creation via the TypeFactory will return a GMPRationalType.
- RationalType creation via the TypeFactory will return a GMPRationalType.
- ComplexType creation via the TypeFactory will return a GMPComplexType.
V2.0.9 fix merge, _{(*95)}
V2.1.0 downgrade library to support PHP5.3 - too many people still using it!, _{(*96)}
V2.1.1 fix PHP5.3 unit tests, _{(*97)}
V2.1.2 remove dependency on Zend\StdLib, _{(*98)}
V2.1.3 refactor for code cleanliness, _{(*99)}
V2.1.4 deprecate Typefactory::setNumberType() method, _{(*100)}
V3.0.0 BC Break: Rename namespace from chippyash\Type to Chippyash\Type, _{(*101)}
V3.0.1 add link to packages, _{(*102)}
V3.0.2 verify PHP7 compatibility, _{(*103)}
V4.0.0 BC Break: end PHP5.3 support. build script changes, _{(*104)}
V4.0.1 update composer - forced by packagist composer.json format change, _{(*105)}
V5.0.0 BC Break: end of support for PHP <5.6, _{(*106)}
V5.1.0 Change of license from GPL V3 to BSD 3 Clause, _{(*107)}