douchungu0859 2019-04-11 14:36
浏览 63

使用可翻译字符串中的占位符遍历对象/访问对象属性

A convenient way to translate dynamic text in applications is to use placeholders, like so:

$message = 'Hello I am {firstname}';
$translation = strtr($message, array('{firstname}', 'John'));

But I want it to be some more dynamicly and just pass a complete person object and the user of the application is free to use whatever he feels comfortable of the person object.

So, given the following object:

$customer = new tstCustomer();
$customer->firstname = 'testfirst';
$customer->lastname = 'testlast';
$customer->email = 'testemail';
class tstCustomer
{
    public $firstname;
    public $lastname;
    public $email;

    public function __construct(){}
}

I want my user to be able to create a translatable string like this:

$message = '{greetings} I am {customer->firstname} {customer->lastname} and my email address is {customer->email} {customer->notexisting}.';

I only have to pass the $customer object now, instead of all kinds of separate properties (and their possible placeholders). That also gives the possibility of object traversing.

echo translation($message, array('{greetings}' => 'Hello World', '{customer}' => $customer));
// Output:
// Hello World I am testfirst testlast and my email address is testemail . 

I've written the following function to accomplish above:

function translation($message, $placeholders = array())
{
    // catch all notices/warnings/errors due to non existent attributes
    $backupHandler = set_error_handler('strtrErrorHandler');

    foreach($placeholders as $placeholder => $value)
    {
        if(gettype($value) === 'string')
        {
            $message = strtr($message, array($placeholder => $value));
            continue;
        }

        if(gettype($value) !== 'object')
            continue;

        $trimmed_placeholder = trim($placeholder, '{}');

        $regex = '/\{'.$trimmed_placeholder.'[\-\>[\w]*]*\}/';
        $matches = array();
        preg_match_all($regex, $message, $matches);
        // $matches should look like:
        // array(1) { [0]=> array(3) { [0]=> string(21) "{customer->firstname}" [1]=> string(20) "{customer->lastname}" [2]=> string(17) "{customer->email}" } } 
        if(!isset($matches[0]))
            continue;

        foreach($matches[0] as $match)
        {
            $stringpath = trim($match, '{}');
            $traversal = substr($stringpath, strlen($trimmed_placeholder)+2); 
            try
            {
                $message = strtr($message, array($match => $value->{$traversal}));
            }
            catch(Exception $e)
            {
                // replace the placeholder with empty string
                $message = strtr($message, array($match => ''));
            }

        }
    } // foreach $placeholders

    set_error_handler($backupHandler);

    return $message;
}
// catch all and convert to a catchable Exception 
function strtrErrorHandler($severity, $message, $filename, $lineno) {
    Yii::log($message, 'error', 'backend.test.index');
    throw new Exception('');
}

Now, my questions:

  1. How safe will this be? (I hope object traversing is limited like this)
  2. Can this be accomplished better in terms of safety?
  3. Can this be accomplished better in terms of performance?
  4. Any other thoughts?
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 数学的三元一次方程求解
    • ¥20 iqoo11 如何下载安装工程模式
    • ¥15 本题的答案是不是有问题
    • ¥15 关于#r语言#的问题:(svydesign)为什么在一个大的数据集中抽取了一个小数据集
    • ¥15 C++使用Gunplot
    • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
    • ¥15 matlab数字图像处理频率域滤波
    • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
    • ¥15 ELGamal和paillier计算效率谁快?
    • ¥15 蓝桥杯单片机第十三届第一场,整点继电器吸合,5s后断开出现了问题