Я думал, что дам этому выстрел с помощью классов и полиморфизма. У меня было предыдущее повторение, которое использовало разделение на подклассы, которое закончило тем, что имело слишком много служебное. Я переключился на более гибкого делегата / объектная модель общественной собственности, которая значительно лучше. Мой код очень немного более точен, мне жаль, что я не мог придумать лучший способ генерировать "несколько месяцев назад", который не казался слишком сверхспроектированным.
я думаю, что все еще придерживался бы Jeff, если тогда каскад, потому что это - меньше кода и это более просто (определенно легче гарантировать, что это будет работать как ожидалось).
Для ниже кода PrintRelativeTime. GetRelativeTimeMessage (Несколько TimeSpan назад) возвраты относительное сообщение времени (например, "вчера").
public class RelativeTimeRange : IComparable
{
public TimeSpan UpperBound { get; set; }
public delegate string RelativeTimeTextDelegate(TimeSpan timeDelta);
public RelativeTimeTextDelegate MessageCreator { get; set; }
public int CompareTo(object obj)
{
if (!(obj is RelativeTimeRange))
{
return 1;
}
// note that this sorts in reverse order to the way you'd expect,
// this saves having to reverse a list later
return (obj as RelativeTimeRange).UpperBound.CompareTo(UpperBound);
}
}
public class PrintRelativeTime
{
private static List<RelativeTimeRange> timeRanges;
static PrintRelativeTime()
{
timeRanges = new List<RelativeTimeRange>{
new RelativeTimeRange
{
UpperBound = TimeSpan.FromSeconds(1),
MessageCreator = (delta) =>
{ return "one second ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromSeconds(60),
MessageCreator = (delta) =>
{ return delta.Seconds + " seconds ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromMinutes(2),
MessageCreator = (delta) =>
{ return "one minute ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromMinutes(60),
MessageCreator = (delta) =>
{ return delta.Minutes + " minutes ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromHours(2),
MessageCreator = (delta) =>
{ return "one hour ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromHours(24),
MessageCreator = (delta) =>
{ return delta.Hours + " hours ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.FromDays(2),
MessageCreator = (delta) =>
{ return "yesterday"; }
},
new RelativeTimeRange
{
UpperBound = DateTime.Now.Subtract(DateTime.Now.AddMonths(-1)),
MessageCreator = (delta) =>
{ return delta.Days + " days ago"; }
},
new RelativeTimeRange
{
UpperBound = DateTime.Now.Subtract(DateTime.Now.AddMonths(-2)),
MessageCreator = (delta) =>
{ return "one month ago"; }
},
new RelativeTimeRange
{
UpperBound = DateTime.Now.Subtract(DateTime.Now.AddYears(-1)),
MessageCreator = (delta) =>
{ return (int)Math.Floor(delta.TotalDays / 30) + " months ago"; }
},
new RelativeTimeRange
{
UpperBound = DateTime.Now.Subtract(DateTime.Now.AddYears(-2)),
MessageCreator = (delta) =>
{ return "one year ago"; }
},
new RelativeTimeRange
{
UpperBound = TimeSpan.MaxValue,
MessageCreator = (delta) =>
{ return (int)Math.Floor(delta.TotalDays / 365.24D) + " years ago"; }
}
};
timeRanges.Sort();
}
public static string GetRelativeTimeMessage(TimeSpan ago)
{
RelativeTimeRange postRelativeDateRange = timeRanges[0];
foreach (var timeRange in timeRanges)
{
if (ago.CompareTo(timeRange.UpperBound) <= 0)
{
postRelativeDateRange = timeRange;
}
}
return postRelativeDateRange.MessageCreator(ago);
}
}
Ознакомьтесь с ob_start , который позволяет передать обработчик обратного вызова для пост-обработки вывода вашего скрипта.
Например, PHP включает встроенный обратный вызов ob_gzhandler для использования при сжатии вывода:
<?php
ob_start("ob_gzhandler");
?>
<html>
<body>
<p>This should be a compressed page.</p>
</html>
<body>
Вот более полный пример, иллюстрирующий, как вы можете привести в порядок свой HTML с помощью tidy extension :
function tidyhtml($input)
{
$config = array(
'indent' => true,
'output-xhtml' => true,
'wrap' => 200);
$tidy = new tidy;
$tidy->parseString($input, $config, 'utf8');
$tidy->cleanRepair();
// Output
return $tidy;
}
ob_start("tidyhtml");
//now output your ugly HTML
Если вы хотите, чтобы все ваши PHP-скрипты использовали тот же фильтр, не включая его напрямую, ознакомьтесь с директивой конфигурации auto_prepend_file .
Вы можете использовать буферизацию вывода и указать обратный вызов при вызове ob_start ()
<?php
function filterOutput($str) {
return strtoupper($str);
}
ob_start('filterOutput');
?>
<html>
some stuff
<?php echo 'hello'; ?>
</html>
Вы можете использовать буферизацию вывода PHP функции для этого
Вы можете предоставить метод обратного вызова, который вызывается при сбросе буфера, например:
<?php
function callback($buffer) {
// replace all the apples with oranges
return (str_replace("apples", "oranges", $buffer));
}
ob_start("callback");
?>
<html>
<body>
<p>It's like comparing apples to oranges.</p>
</body>
</html>
<?php
ob_end_flush();
?>
В этом случае вывод буферизируется, а не отправляется из сценария и непосредственно перед сбросом вашего метода обратного вызова называется.
Посмотрите, как используется Smarty . Это система шаблонов для PHP, которую рекомендуется использовать, и к которой вы можете подключить глобальные фильтры вывода.
править: ответ Пола лучше. Итак, это будет
ob_start("my_filter_function");
Мой первоначальный ответ был:
Этого можно достичь с помощью буферизации вывода .
Например:
ob_start();
// Generate all output
echo "all my output comes here."
// Done, filtering now
$contents = ob_get_contents();
ob_end_clean();
echo my_filter_function($contents);