Classes and data classes
Classes
A class can declare its constructor parameters right after its name: the primary constructor. Parameters marked val or var become properties.
class User(val id: Int, var $name: String) {
function rename(to: String): Unit {
$name = to
}
function label(): String = "${name} (#${id})"
}
val u = new User(1, "Ada")
u->rename("Ada L.")
echo u->label()Objects are created with new, as in PHP.
Properties
Properties follow the binding rules: val properties can't be assigned after construction, var $name properties can. Inside the class they are available without $this->, and the sigil still tells them apart:
class Counter {
var $count: Int = 0
val step: Int = 2
function tick(): Unit {
$count += step // $this->count += $this->step
}
function reset(): Unit {
step = 1 // error: SPHP0010
}
}When a parameter has the same name as a property, name is the parameter and $name the mutable property: $name = name assigns one to the other.
Visibility is public by default; private and protected work as in PHP. Static members use static and are reached with ClassName::member.
Methods
Methods can be called without $this-> too, if the arguments fit. If they don't, a bare call means PHP's global function of that name, which is how a count() method can use PHP's count. $this->name() always means the method:
class Cart {
private var $items: array<string> = []
function count(): int = count($items)
function isEmpty(): bool = $this->count() === 0
}Final by default
Classes and their methods are final unless marked open (or abstract). An overriding method is marked override:
open class Shape(val name: String) {
open function area(): Float = 0.0
function describe(): String = "${name}: ${area()}"
}
class Circle(val r: Float) : Shape("circle") {
override function area(): Float = 3.14159 * r * r
}
class Square : Shape("square") {
override function size(): Int = 1 // error: SPHP0031
}The superclass and interfaces come after a colon; a superclass is followed by its constructor arguments. abstract classes and interfaces work as in PHP.
In the generated PHP, a class that isn't open is final, and so are its methods. What a subclass can override carries its type in PHPDoc only, so plain PHP subclasses can override it without type declarations: the return types of open, abstract and interface methods, and the types of var properties that subclasses can see.
Data classes
A data class is an immutable value object. All its properties are val, and it compiles to a final readonly PHP class:
data class Money(val cents: Int, val currency: String)
val price = new Money(1999, "EUR")
echo price->centsSealed hierarchies
A sealed class or interface lists its subclasses implicitly: only classes in the same project may extend it, so when can check that every case is handled. See when, is and smart casts.
sealed interface Shape
data class Circle(val r: Float) : Shape
data class Rect(val w: Float, val h: Float) : Shape
function area(s: Shape): Float = when (s) {
is Circle -> 3.14159 * s->r * s->r
is Rect -> s->w * s->h
}Enums
Enums are PHP's enums:
enum Suit: string {
case Hearts = "H"
case Spades = "S"
}
echo Suit::Hearts->value