Свойства   


@GET_имя[]
код, выдает значение

@SET_имя[value]
код, обрабатывает новое $value

@GET_DEFAULT[]   
@GET_DEFAULT[имя]
   

код, обрабатывающий обращения к несуществующим полям


@SET_DEFAULT[имя;значение]   

код, обрабатывающий запись в несуществующие поля


@GET[]
   

@GET[
тип обращения]

код, 
обрабатывающий обращения к объекту/классу в определённых контекстах вызова


Можно определить default getter (
@GET_DEFAULT[]) - метод, который будет вызываться при обращении к несуществующим полям. Имя поля, к которому пытались обратиться, передаётся единственным параметром этому методу.
Важно: с этим методом нельзя работать как с обычным «свойством», при попытке написать $DEFAULT будет выдано сообщение об ошибке.

Также можно определить default setter (
@SET_DEFAULT[name;value]) - метод, который будет вызываться при попытках записи в несуществующие поля. Имя поля, к которому пытались обратиться и записываемое значение будут переданы этому методу.

У пользовательских классов можно определить специальное свойство
@GET[], которое будет вызываться при обращении к классу/объекту этого класса в определённых контекстах вызова, например: в скалярном контексте, в выражении и т.п. Если у этого свойства определён параметр, то через него будет передан тип обращения, который может принимать одно из следующих значений: def, expression, bool, double, hash, table или file.

Примечание: при обычном присваивании вида $a[$b] метод @GET[] не вызывается.

Так названные методы задают «свойство», которым можно пользоваться, как обычной переменной:
пишем
происходит
$имя
^GET_имя[]
$имя[значение]
^SET_имя[значение]

Примечание: если не требуется возможность записи или чтения свойства, соответствующий метод можно не определять.
Важно: нельзя иметь и свойство и переменную с одним именем.


Пример: возраст и e-mail
Возьмем человека - хранить удобно дату рождения, а выводить частенько нужно возраст. Нужен e-mail, но можно позабыть проверить его на корректность.

Пусть людьми занимается класс, его свойства «возраст» и «e-mail» позволят спрятать ненужные детали, сделав код проще и нагляднее:
@USE
/person.p

@main[]
$person[^person::create[
    $.name[
Василий Пупкин]
    $.birthday[^
date::create(2000;8;5)]
]]
# можно менять, но значение проверят
$person.email[
vasya@pupkin.ru]
$person.name
 ($person.email), возраст: $person.age<br />
Выведет:
Василий Пупкин (vasya@pupkin.ru), возраст: 5<br /> (с ходом времени возраст будет увеличиваться)
При этом менять возраст человека нельзя:
# это вызовет ошибку!
$person.age(
99)

Также нельзя присваивать свойству email некорректные значения:
# это вызовет ошибку!
$person.email[
vasya#pupkin.ru]

Определение класса person
Чтобы вышеописанный пример сработал, нужно определить класс person и его свойства.
В корне веб-пространства в файл
person.p поместим это:
@CLASS
person

@create[p]
$name[$p.name]
$birthday[$p.birthday]

# свойство «возраст»
@GET_age[]
[now;today;celebday]
$now[^date::
now[]]
$today[^date::create($now.
year;$now.month;$now.day)]
$celebday[^date::create($now.year;$birthday.month;$birthday.day)]
# числовое значение логического выражения: истина=1; ложь=0
$
result(^if($birthday>$today)(0)($today.year - $birthday.year - ($today<$celebday)))

# свойство «e-mail»
@SET_email[value]
^if(
!^Lib:isEmail[$value]){
    ^
throw[email.invalid;Некорректный e-mail: '$value']
}
# имя переменной не должно совпадать с именем свойства!
$private_email[$value]

@GET_email[]
$private_email

Примечание: метод isEmail
, как и ряд других полезных методов и операторов можно скачать по следующему адресу: http://www.parser.ru/examples/lib/.
Примечание: классы лучше помещать в отдельное удобное место и при подключении не указывать путь, см.
$CLASS_PATH.


Пример: класс, расширяющий функционал системного класса table
@main[]
$t[^MyTable::create{a   b
0a   0b
1a   1
b
2a   2b
3a   3b}]

Значение в выражении: ^eval($t)<br />
^^t.count: ^t.count[]<br />
Выводим содержимое пользовательского объекта: ^print[$t]<br />


<br />
Копируем объект и выводим ^^c.count[]:
$c[^MyTable::create[$t]]
^c.count[]<br />
Удаляем 2 строки, начиная со строки с offset=1 и выводим содержимое пользовательского объекта:
^c.remove(1;2)
^print[$c]<br />


<br />
Создаём объект системного класса table на основании объекта класса MyTable и выводим ^^z.count[]:
$z[^table::create[$t]]
^z.count[]<br />


@print[t]
^t.menu{$t.a=$t.b}[<br />]


Определение класса MyTable
@CLASS
MyTable

@create[uParam]
^switch[$uParam.CLASS_NAME]{
   ^case[string]{$t[^table::create{$uParam}]}
   ^case[table;MyTable]{$t[^table::create[$uParam]]}
   ^case[DEFAULT]{^throw[MyTable;
Unsupported type $uParam.CLASS_NAME]}
}

# метод возвращающий значение объекта в разных контекстах вызова
@GET[
sMode]
^switch[$sMode]{
   ^case[table]{$result[$t]}
   ^case[bool]{$result($t!=0)}
   ^case[def]{$result(true)}
   ^case[expression;double]{$result($t)}
   ^case[DEFAULT]{^throw[MyTable;Unsupported mode '$sMode']}
}



# метод обрабатывает обращения к "столбцам"
@GET_DEFAULT[sName]
$result[$t.$sName]


# для всех существующих методов нужно написать wrapper-ы
@count[]
^t.count[]

@menu[jCode;sSeparator]
^t.menu{$jCode}[$sSeparator]


# добавляем новый функционал
@remove[iOffset;iLimit]
$iLimit(^iLimit.int(0))
$t[^t.select(^t.offset[]<$iOffset || ^t.offset[]>=$iOffset+$iLimit)]



User comments:

G_Z 06 октября 2008 19:23

Можно определить default getter (@GET_DEFAULT[имя]) - метод, который будет вызываться при обращении к несуществующим полям. Имя поля, к которому пытались обратиться, передаётся в единственном параметре этого метода.


В версии 3.3.0 ошибка: парамер метода @GET_DEFAULT[имя] возвращает не имя свойства, а «GET_имя_свойства».

    Поддержать сайт на родительском проекте КГБ