Свойства
@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 1b
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_имя_свойства». |