Basics
Contents
Scope of this document
This document is intended to cover the basics.
Encapsulation
Phoebius framework is object-oriented. This means that classes here are everything.
We really love how C# and Java helps us to solve the dependencies, and hate the tons
of include's and require's we need to write in PHP. Thus
we decided to oversimplify this:
- you do not need to include scripts with classes you wish to use;
- class files must be defined in a separate file which is located anywhere
under the directory which is specified inside the
include_path. A file naming pattern is<ClassName>.class.php(case-sensitive!).
MyController, it is reasonable to
put it within $app/lib/Mvc/MyController.class.php and it will be found
automatically on it's first usage (because $app/lib is added to
include_path by default). Then a class loader, that is initialized in core init-script, takes care about the look up.
Fail-save code
An application flow is exception-centric: each PHP's error/warning/notice is replaced with an exception object. Such a concept helps to avoid tons of unnoticeable inconsistencies (like an access to undefined index of an array) and thus making the usage of an internal PHP function strong enough and unambiguous. The following example proves that you won't forget to do the check:
try {
// suppressing errors via "@" won't help you here wrt. error verbosity
unlink('/path/to/nonexistent.file');
}
catch (ExecutionContextException $e) {
// handle this gracefully
}
Of course, this functionality can be explicitly turned off when using a third-party library that does not know about the
exceptions or ignores notices and warnings (e.g., PEAR). Phoebius defines two exceptions that are used to wrap internal errors:
-
ExecutionContextExceptionis used to replace all PHP errors, warnings and notices except fatal. -
CompilationContextException is used define a fatal error (this
also includes
E_USER_ERRORtriggered using trigger_error. This kind of exception should be caught inside front-controller only and than handled as unexpected error. This is done bySiteApplication, as described by the "Application init" manual.
Assertions
In some cases you cannot rely on type-checks only: there are a lot of cases when you need to be sured that the control flow is predictable. This is true especially for loosely-typed languages.
For this reasons Phoebius introduces an assertion module: a set of easy-to-use
routines that may be used in every corner case. They are wrapped by an Assert class. Each of the public static method accepts an
expression to assert, the message to show if assertion fails, and an optional
arguments to be interpolated within a message through the sprintf call. For example:
function setGreedy($flag) {
Assert::isBoolean(
$flag,
'greedyness should be boolean, %s is given',
TypeUtils::getName($flag) // may name a class, a scalar or even a null
);
Assert::isTrue(
$this->mayHaveGreedyNess,
'you cannot set greedyness here'
);
...
}
Assert gives the following methods to assert an expressions:
isTrue,isFalseto check whether expression is true or falseisCallbackto determine whether an expression is callableisEmpty,isNotEmptyto determine whether expression is empty or not (empty()operator is used, so all types of variables are accepted)isNull,isNotNull,isScalarOrNullisResourceisNumeric,isInteger,isPositiveInteger,isFloatisScalarisBoolean
There are also some extra methods, which stop the execution in any case: if they are
called then it is meant that assertion fails. They are isUnreachable
and notImplemented:
try {
return do_some_stuff();
Assert::isUnreachable();
}
catch (Exception $e) {
Assert::notImplemented(); // do not forget to implement!
}
Enumerations
While PHP is a loosely-typed language, it does not provide a good base type system, which is presented in other object-oriented languages. In many cases it misses an enumerations, which commonly help to check implicitly whether a passed value is in the set of predefined values.
Phoebius provides an advanced replacement for enumerations with a base Enumeration class.
When you need to define a set of values and gracefuly check whether a coming value
is from the predefined set, you just create a descendant of Enumeration and define a desired constants inside it:
Color.class.php
class Color extends Enumeration
{
const RED = 'color_red';
const WHITE = 'color_white';
const BLACK = 'color_black';
}
Then you can refer to it and use it as follows:
function setColor(Color $color)
{
echo 'Setting a desired color: ', $color->getValue();
}
// prints "Setting a desired color: color_white"
setColor(new Color(Color::WHITE));
To avoid a code mess that makes an instance of enumeration, you can use the following hint making a static method for every commonly-used constant:
class Color extends Enumeration
{
const RED = 'color_red';
const WHITE = 'color_white';
const BLACK = 'color_black';
/**
* @return Color
*/
static function red()
{
return new self (self::RED);
}
/**
* @return Color
*/
static function white()
{
return new self (self::WHITE);
}
/**
* @return Color
*/
static function black()
{
return new self (self::BLACK);
}
}
// usage:
$color = Color::black();
Enumerations is an extremely used feature inside Phoebius to provide extra type checks here and there (see the inheritance diagram).
