Прежде чем перейти непосредственно к сути созданной темы хочу позволить себе немного лирики. Следующие слова изначально не планировались, но после 3-х дневной работы над этой задачей у меня появились определенные впечатления от ее решения. Сразу скажу, что ни в один момент не появилось желания все бросить и "забить", не появилось желания списать готовое решение. Кроме того мой опыт ничтожно мал и мне хотелось самому выполнить все условия, которые предлагались.
Не скрою, что самой большой мотивацией для меня было попытаться догнать более опытных товарищей и возможность на попадание так называемой доски "почета". (Т.е в список тех, кто решил эту задачу).
При проверке моего решения прошу учесть, что занимаюсь обучением 2 месяца, но правда очень плотно. Это я к тому, что я просто элементарно могу не знать как написать некоторые строчки кода оптимальней, чем я это сделал на текущий момент. Итак приступим... Что сделано?
Условие задачи.
Написать скрипт регистрации. Он должен:
1. Сохранять в базе MySQL имя, полученное из формы методом POSTВыполнено
2. Выводить список всех зарегистрировавшихся пользователей в обратном порядке, последнего зарегистрировавшегося на первом месте.Выполнено
3. Имена в списке должны быть представлены в виде ссылок, при нажатии на которую должна появится дата регистрации.Частично выполнено.
Решение отличается от требуемого, но функционал достигнут согласно требованию
4. Иметь поисковик, который должен осуществлять поиск по полю с именами и выводить все имеющиеся совпадения (по части слова).Выполнено
Требования.
1. В имени могут присутствовать абсолютно любые символы, включая пробел. Исключением является только пробел в чистом виде, без других символов.
Выполнено.
Пробел в чистом виде также работает корректно
2. Имя должно выводиться в браузер без искажений.
Выполнено
3. При осуществлении поиска слово, набранное в поле, должно возвращаться обратно в форму.
Выполнено.
Также корректно возвращаются в форму двойные кавычки и ноль
4. Форма поиска должна отправляться методом GET
Выполнено
5. Скрипт не должен зависеть от настройки magic_quotes.
Выполнено
Безопасность
1. Скрипт должен быть защищен от SQL-инъекций
Выполнено
2. Должна быть защита от F5
Выполнено
3. Страница должна быть защищена от XSS атак.
Выполнено
Кроме того важны оптимальность, читабельность и стиль написания.
Старался сделать максимально читабельно, но в тоже время максимально универсально, насколько позволяют мои скудные знания.
Вложенным архивом я прилагаю все исходники для таких же новичков. Только измените параметры подключения к базе данных на свои.
Следующим постом я выложу листинг
Спустя 7 минут, 59 секунд (18.09.2012 - 08:57) NierRa написал(а):
На этом бесплатном хостинге можно проверить работу скрипта любому желающему, найти ошибки и раскритиковать код
Часть 1
index.php
db.php
language_ru.php
Часть 1
index.php
<?php
error_reporting(E_ALL);
define('ROOT_CATALOG', dirname(__FILE__).DIRECTORY_SEPARATOR);
require ROOT_CATALOG.'language_ru.php';
require ROOT_CATALOG.'db.php';
require ROOT_CATALOG.'functions.php';
require ROOT_CATALOG.'form.php';
db.php
<?php
/* Переключатель уровня ошибок */
## 1. Определена = уровень разработчика
## 2. НЕ Определена = уровень пользователя
//define('DB_DISPLAY_ERRORS', TRUE);
/* Параметры подключения к базе данных MYSQL */
define('DB_HOST', 'mysql.hostinger.com.ua');
define('DB_LOGIN', 'u447206004_user');
define('DB_PASS', 'wk32584zaf');
define('DB_NAME', 'u447206004_names');
/* Функция отображения ошибок пользователю при взаимодействии с базой данных mySQL */
function db_connect_error ($action = TRUE) {
if(defined('DB_DISPLAY_ERRORS')) {
die(mysql_error());
}
else {
switch($action) {
case 'insert':
die(DB_ERROR_INSERT);
break;
case 'update':
die(DB_ERROR_UPDATE);
break;
case 'delete':
die(DB_ERROR_DELETE);
break;
default:
die(DB_ERROR_DEFAULT);
}
}
}
/* Скрипт подключения к базе данных mySQL */
$connect = mysql_connect(DB_HOST, DB_LOGIN, DB_PASS) or call_user_func('db_connect_error');
mysql_select_db (DB_NAME, $connect)
or call_user_func('db_connect_error');
mysql_set_charset('utf8')
or call_user_func('db_connect_error');
language_ru.php
<?php
/* Общие константы */
define('TITLE', 'Задача на корректную обработку данных');
define('PLACEHOLDER_ENTER_NAME', 'Введите имя');
/* Константы вывода ошибок базы данных */
define('DB_ERROR_DEFAULT', 'Произошла ошибка соединения с базой данных mySQL');
define('DB_ERROR_INSERT', 'Произошла ошибка записи в базу данных mySQL');
define('DB_ERROR_UPDATE', 'Произошла ошибка обновления базы данных mySQL');
define('DB_ERROR_DELETE', 'Произошла ошибка удаления записи с базы данных mySQL');
/* Константы формы со списками пользователей */
define('USER_BUTTON_SAVE', 'Сохранить');
define('USER_LIST', 'Список зарегистрированных пользователей');
define('USER_LIST_EMPTY', 'На данный момент в базе нет зарегистрированных пользователей');
define('USER_LIST_TOTAL', 'Всего пользователей');
define('USER_LIST_LAST', 'Последний пользователь');
define('NEW_USER_LABEL', 'Регистрация нового пользователя');
define('NEW_USER_REG_ERR_TITLE', 'Ошибка при регистрации нового пользователя');
define('NEW_USER_REG_ERR_REASON', 'Имя пользователя не может содержать только одни пробелы');
/* Константы поиска */
define('SEARCH_FIELD_LABEL', 'Поиск');
define('SEARCH_BUTTON_FIND', 'Найти');
define('SEARCH_BUTTON_REFRESH', 'Обновить');
define('SEARCH_MATCH', 'Список соответствия');
define('SEARCH_FOUND', 'Найдено совпадений');
Спустя 18 минут, 5 секунд (18.09.2012 - 09:15) NierRa написал(а):
Часть 2
form.php
functions.php
form.php
<?php
/* Обработчик формы */
if($_SERVER['REQUEST_METHOD'] === 'POST') :
/* Инициализация данных с формы */
$user = !empty($_POST['name']) ? $_POST['name'] : NULL; // Имя пользователя
/* Обработка данных, если директива GET_MAGIC_QUOTES включена */
if(get_magic_quotes_gpc())
$user = call_user_func('data_processing', $user);
else
$user = call_user_func('data_processing', $user, $flag = FALSE);
/* Редирект с ошибкой, если имя пользователя содержит проблел в чистом виде */
if(empty($user)) {
header('location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?reg=error');
exit();
}
/* Сохранение нового пользователя в БД */
call_user_func('save_new_user', $user);
endif;
/* Инициализация GET данных */
$error = !empty($_GET['reg']) ? TRUE : NULL; // Ошибка при неудачной регистрации
$user = !empty($_GET['user']) ? $_GET['user'] : NULL; // id пользователя
$submit = !empty($_GET['submit']) ? $_GET['submit'] : NULL; // Проверка на нажатие кнопки поиска
$search = !empty($_GET['search']) ? $_GET['search'] : NULL; // Данные с формы поиска
if(get_magic_quotes_gpc())
$search = call_user_func('data_processing', $search);
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title><?= TITLE ?></title>
<link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<!--Список всех зарегистрированных пользователей -->
<div id="view">
<fieldset class="left"><legend><?= NEW_USER_LABEL ?></legend>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="POST">
<input type="text" name="name" placeholder="<?= PLACEHOLDER_ENTER_NAME ?>" required>
<input type="submit" value="<?= USER_BUTTON_SAVE ?>">
<input type="button" value="<?= SEARCH_BUTTON_REFRESH ?>"
onclick="location.href='<?= $_SERVER['PHP_SELF'] ?>'">
<?php /* Вывод ошибки в случае неудачной регистрации нового пользователя */
if($error)
echo '<br /><span class="error">'.NEW_USER_REG_ERR_TITLE.'</span><br />
<span class="err_reason">'.NEW_USER_REG_ERR_REASON.'</span>'; ?>
</form>
</fieldset>
<fieldset class="left"><legend><?= USER_LIST ?></legend>
<!-- Вывод списка всех зарегистрированных пользователей -->
<?= call_user_func('get_total_user_list') ?>
</fieldset>
</div> <!-- endClass #view -->
<div id="search">
<fieldset class="right"><legend><?= SEARCH_FIELD_LABEL ?></legend>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="GET">
<input type="text" name="search"
<?= /* Возвращение значения, запрошенного пользователем в строке поиска */
call_user_func('return_data', $search, $submit); ?> required>
<input type="submit" name="submit" value="<?= SEARCH_BUTTON_FIND ?>">
<input type="button" value="<?= SEARCH_BUTTON_REFRESH ?>"
onclick="location.href='<?= $_SERVER['PHP_SELF'] ?>'">
</form>
</fieldset>
<fieldset class="right"><legend><?= SEARCH_MATCH ?></legend>
<?php
if(!empty($search))
/* Формирование запроса в строке поиска пользователей */
call_user_func('get_search', $search, $submit);
else
/* Костыль на корректное формирование запроса с символом 0(ноль) */
call_user_func('get_search', TRUE, $submit);
?>
</fieldset>
</div> <!-- endClass #search -->
<!-- Костыль для корректного отображения тултипа последних пользователей
(только для экономии времени при решении данной задачи) -->
<div class="clear"></div>
<div id="patch"></div>
</body>
</html>
functions.php
<?php
#####
##### Функции подготовки/реализации данных для ВВОДА #####
#####
/* Функция обработки данных... */
function data_processing($data, $flag = TRUE) {
if($flag)
/* ...в случае, если директива GET_MAGIC_QUOTES включена */
return $data = trim(stripslashes($data));
else
/* ...во всех остальных случаях */
return $data = trim($data);
} /* endFunction */
/* Функция сохранения нового пользователя в БД */
function save_new_user($user) {
$query = "INSERT INTO `names`(`name`) VALUES ('".mysql_real_escape_string($user)."')";
$sql = mysql_query($query) or call_user_func('db_connect_error', 'insert');
if($sql) {
header('location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']);
exit();
}
else {
header('location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?reg=error');
exit();
}
} /* endFunction */
#####
##### Функции подготовки/реализации данных для ВЫВОДА #####
#####
/* Функция вывода всех зарегистрированных пользователей */
function get_total_user_list() {
$query = "SELECT `name`, `id`, `date`
FROM `names`
ORDER BY `id` DESC";
$sql = mysql_query($query) or call_user_func('db_connect_error');
if(!mysql_num_rows($sql)) {
/* Инструкция на случай пустого поля со списком зарегистрированных пользователей */
echo '<blockquote><h4>'.USER_LIST_EMPTY.':</h4></blockquote>';
}
else {
/* Вывод последнего зарегистрированного пользователя */
echo '<blockquote><h4>'.USER_LIST_LAST.': </h4>'
.htmlspecialchars(mysql_result($sql, 0)).'</blockquote>';
/* Вывод общего количества зарегистрированного пользователя */
echo '<blockquote><h4>'.USER_LIST_TOTAL.': </h4>'.mysql_num_rows($sql).'</blockquote>';
mysql_data_seek($sql, 0); // Смещение указателя в начало массива
while($res = mysql_fetch_assoc($sql)) {
echo '<em class="tooltip">'.htmlspecialchars($res['name']).'
<span class="classic">Дата регистрации: '.$res['date'].'</span></em><br />';
}
}
} /* endFunction */
/* Функция поиска зарегистрированных пользователей в БД */
function get_search($search, $submit) {
if($submit) :
/* Обработка специальных(служебных) символов */
$search = mysql_real_escape_string(addcslashes($search, "\\%_'"));
$query = "SELECT `name`, `date`
FROM `names`
WHERE `name`
LIKE '%".$search."%'
ORDER BY `date` DESC";
$sql = mysql_query($query) or call_user_func('db_connect_error');
/* Вывод чилового значения пользователей, удовлетворяющих условию запроса поиска */
echo '<blockquote><h4>'.SEARCH_FOUND.': '.mysql_num_rows($sql).'</h4></blockquote>';
while($res = mysql_fetch_assoc($sql)) {
/* Вывод списка пользователей, удовлетворяющих условию запроса поиска */
echo '<em class="tooltip">'.htmlspecialchars($res['name']).'
<span class="classic">Дата регистрации: '.$res['date'].'</span></em><br />';
}
endif;
} /* endFunction */
/* Функция возвращения значения, запрошенного пользователем в строке поиска */
function return_data($search, $submit) {
/* Вывод дефолтного значения(по умолчанию) - пустой строки с меткой(placeholder) */
if(empty($search) && empty($submit))
return $search = 'placeholder="'.PLACEHOLDER_ENTER_NAME.'"';
/* Вывод всех данных в поле запроса, после формирования последнего */
elseif($submit && $search)
return $search = 'value="'.htmlspecialchars($search).'"';
/* Костыль для вывода символа 0(ноль) в поле запроса */
elseif(empty($search) && $submit) {
return $search = 'value="0"';
}
} /* endFunction */
Спустя 1 минута, 7 секунд (18.09.2012 - 09:16) NierRa написал(а):
Часть 3
.htaccess
style.css
.htaccess
AddType application/x-httpd-php .html .htm .php .php3
AddDefaultCharset UTF-8
php_flag short_open_tag On
php_flag magic_quotes_gpc Off
php_flag magic_quotes_runtime Off
php_flag register_globals Off
php_flag output_buffering Off
style.css
body {
font: 1em 'Bookman Old Style', monospace;
color: #000;
}
em {
font: normal 1em 'Bookman Old Style', monospace;
text-decoration: none;
color: #000;
}
em:hover {
color: #F00;
}
blockquote h4 {
display: inline;
line-height: 70%;
margin-right: 10px;
}
/* Детальная информация пользователя */
.tooltip {
cursor: default;
position: relative;
}
.tooltip span {
margin-left: -999em;
position: absolute;
}
.tooltip:hover span {
border: 1px solid rgba(155, 155, 155, 0.8);
border-radius: 5px 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
-webkit-box-shadow: 5px 5px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 5px 5px rgba(0, 0, 0, 0.1);
position: absolute; left:3em; top: 2em; z-index: 99;
margin-left: 0; width: 250px;
background: #CCC;
color: #000;
}
.classic {
padding: 0.8em 1em;
}
/* endLast */
/* Блок вывода/регистрации пользователей */
#view {
float: left;
}
#view .left {
width: 600px;
margin: 20px;
}
#view .left .error {
font-size: 0.8em;
color: #F00;
margin-left: 10px;
}
#view .left .err_reason {
font-size: 0.8em;
color: #F00;
margin-left: 10px;
}
/* endLast */
/* Блок поиска пользователей */
#search {
float: right;
}
#search .right {
width: 400px;
margin: 20px;
}
/* endLast */
/* Служебные */
.clear {
clear: both;
}
#patch {
height: 75px;
}
/* endLast */
Спустя 1 минута, 59 секунд (18.09.2012 - 09:18) NierRa написал(а):
Это все. Сразу отвечу на возможный вопрос...
Мне просто нравится использовать call_user_func
Жду критики, благодарю!
Мне просто нравится использовать call_user_func
Жду критики, благодарю!
Спустя 3 часа, 37 минут, 27 секунд (18.09.2012 - 12:55) twin написал(а):
Основательный подход. Респектище. Как говаривал мой дед - делать нужно стараться хорошо. Плохо - оно само получится. Если что-то делать, то стоит сделать это по полной программе. И самому приятно и людям радость.
Вобщем то придраться не к чиму, все на 5. Одна мелкая ошибка, одно уточнение, один вопрос и один совет.
1. Функции mysql_connect() и mysql_select_db() при отсутствии коннекта или базы выбрасывают Warning, а значит, если используется OR DIE, то нужно глушить его собачкой. Иначе он полезет на экран. Попробуй написать левй хост в настройках - увидишь. Но это не самое страшное. Страшнее то, что ты в аргумент switch() суешь миксованные типы данных. А он работает как простое равенство. То есть при отсутствии коннекта мы получим сообщение не
Вобщем то придраться не к чиму, все на 5. Одна мелкая ошибка, одно уточнение, один вопрос и один совет.
1. Функции mysql_connect() и mysql_select_db() при отсутствии коннекта или базы выбрасывают Warning, а значит, если используется OR DIE, то нужно глушить его собачкой. Иначе он полезет на экран. Попробуй написать левй хост в настройках - увидишь. Но это не самое страшное. Страшнее то, что ты в аргумент switch() суешь миксованные типы данных. А он работает как простое равенство. То есть при отсутствии коннекта мы получим сообщение не
Цитата |
Произошла ошибка соединения с базой данных mySQL |
как ты ожидаешь из дефолта, а
Цитата |
Произошла ошибка записи в базу данных mySQL |
, потому что она первая в кейсах. А это не соответствует действительности))) Потому что 'insert' == true
Это конечно не критично, но говорит о пробеле знаний в этой области.
2.
Это конечно не критично, но говорит о пробеле знаний в этой области.
2.
Цитата |
3. Имена в списке должны быть представлены в виде ссылок, при нажатии на которую должна появится дата регистрации. Частично выполнено. Решение отличается от требуемого, но функционал достигнут согласно требованию |
Тут перестарался. Дело было не в том, чтобы увидеть дату регистрации. Я понимаю, что так вроде оно поинтереснее. Дело в том, чтобы проверить полный набор методов обработки данных. А в твоем решении нет обработки целочисленных данных для запроса. Учитывая уровень конечно понятно, что это не вызвало бы затруднений, но такой подход может принести непредсказуемые результаты. Самостоятельное изменение ТЗ - плохая практика. Ведь можно не учесть кучи подводных камней. Что и произошло. Вроде как задача решена, а суть исковеркана.
3. А чем так обусловлена любовь к call_user_func()? Ведь это перерасход памяти, теряется читабельность... Может я чего-то упустил? В чем прикол?
4. Вот это можно проще делать:
Ну и последний совет шепотом:
А вообще повторюсь - респект. Работа просто отличная.
3. А чем так обусловлена любовь к call_user_func()? Ведь это перерасход памяти, теряется читабельность... Может я чего-то упустил? В чем прикол?
4. Вот это можно проще делать:
$error = !empty($_GET['reg']) ? TRUE : NULL; // Ошибка при неудачной регистрациивот так:
$error = !empty($_GET['reg']); // Ошибка при неудачной регистрацииВообще часто можно встретить дубляж возвратов (не у тебя, я вообще про всех) там, где они не нужны. Допустим вот это место:
/* Функция отображения ошибок пользователю при взаимодействии с базой данных mySQL */лаконичнее смотрится так:
function db_connect_error ($action = TRUE) {
if(defined('DB_DISPLAY_ERRORS')) {
die(mysql_error());
}
else {
/* Функция отображения ошибок пользователю при взаимодействии с базой данных mySQL */
function db_connect_error ($action = TRUE) {
!defined('DB_DISPLAY_ERRORS') or die(mysql_error());
Ну и последний совет шепотом:
Свернутый текст
Не выкладывай на всеобщее обозрение данные коннектов. Я понимаю что плевать - халявный хостинг. Но это привычка - все держать под контролем.
А вообще повторюсь - респект. Работа просто отличная.
Спустя 5 часов, 29 минут, 5 секунд (18.09.2012 - 18:24) NierRa написал(а):
Благодарю за ответ!
Пункт 1 и 2 учту. Выкладывать исправленный вариант уже не буду, чтобы не занимать место. Да и пусть новички видят в чем была суть замечаний. У себя же в скрипте исправлю
По call_user_func у меня есть пару аргументов. Для меня нагляднее смотрится call_user_func('goto_point') чем goto_point() Почему?
1. Поиск в любом редакторе (Ctrl+F) позволяет быстро найти все вызовы функций (по кнопке "Выбрать все"). Может это и не оправдано, но мне как новичку, начавшему писать достаточно крупный проект (в образовательных целях) это очень помогает
2. Мне нравится подсветка кода, когда используется call_user_func. Dreamweaver CS5.5 в силу понятных причин просто не может отличить вызов функции без использования call_user_func от обычных ключевых слов и это мне доставляет определенные неудобства и очень злит
3. Пару лет назад занимался мапмейкингом в Warcraft 3. Там в jass мне понравился синтаксис, используемый в функциях.
Мне показалось ключевое слово call (с англ. "Вызвать") очень точно отображает суть. Еще будучи абсолютным нулем в PHP я очень хотел, чтобы и тут была возможность каким то образом завернуть вызов функции в ключевое слово. Если вы заметили, у меня в конце каждой функции стоит комментарий /* endFunction */, теперь можно понять откуда :)
Возможно это не самые убедительные аргументы, но на форумах не нашел каких либо сведений об ущебности данного способа.
По пункту 4 - изначально вместо TRUE было другое значение. Скажем так, в процессе нескольких модификаций тернарная операция приняла текущий вид и я просто не сообразил, что можно теперь успростить код.
По совету под спойлером - я очень долго думал выкладывать параметры подключений или нет и мне показалось, что для анализа тестовой работы должны быть выложены все данные. В любой момент можно на живом хостинге внести изменения и посмотреть реакцию интерпретатора
Еще раз благодарю за критику. Очень полезная практика для начинающего WEB-разработчика. Особенно, если решил сам
Пункт 1 и 2 учту. Выкладывать исправленный вариант уже не буду, чтобы не занимать место. Да и пусть новички видят в чем была суть замечаний. У себя же в скрипте исправлю
По call_user_func у меня есть пару аргументов. Для меня нагляднее смотрится call_user_func('goto_point') чем goto_point() Почему?
1. Поиск в любом редакторе (Ctrl+F) позволяет быстро найти все вызовы функций (по кнопке "Выбрать все"). Может это и не оправдано, но мне как новичку, начавшему писать достаточно крупный проект (в образовательных целях) это очень помогает
2. Мне нравится подсветка кода, когда используется call_user_func. Dreamweaver CS5.5 в силу понятных причин просто не может отличить вызов функции без использования call_user_func от обычных ключевых слов и это мне доставляет определенные неудобства и очень злит
3. Пару лет назад занимался мапмейкингом в Warcraft 3. Там в jass мне понравился синтаксис, используемый в функциях.
function HelloWorld takes player p returns nothing
call DisplayTextToPlayer(p, 0, 0, "Hello World!")
endfunction
Мне показалось ключевое слово call (с англ. "Вызвать") очень точно отображает суть. Еще будучи абсолютным нулем в PHP я очень хотел, чтобы и тут была возможность каким то образом завернуть вызов функции в ключевое слово. Если вы заметили, у меня в конце каждой функции стоит комментарий /* endFunction */, теперь можно понять откуда :)
Возможно это не самые убедительные аргументы, но на форумах не нашел каких либо сведений об ущебности данного способа.
По пункту 4 - изначально вместо TRUE было другое значение. Скажем так, в процессе нескольких модификаций тернарная операция приняла текущий вид и я просто не сообразил, что можно теперь успростить код.
По совету под спойлером - я очень долго думал выкладывать параметры подключений или нет и мне показалось, что для анализа тестовой работы должны быть выложены все данные. В любой момент можно на живом хостинге внести изменения и посмотреть реакцию интерпретатора
Еще раз благодарю за критику. Очень полезная практика для начинающего WEB-разработчика. Особенно, если решил сам
Спустя 20 минут, 57 секунд (18.09.2012 - 18:45) NierRa написал(а):
Вспомнил что хотел спросить. У меня вывод даты с БД не обработан.
Подскажите как обработать вывод даты с поля (TIMESTAMP)
Подскажите как обработать вывод даты с поля (TIMESTAMP)
Спустя 1 час, 4 минуты, 1 секунда (18.09.2012 - 19:49) twin написал(а):
Этого не требуется. Дело в том, что поле типа DATE и иже с ним не примет никакого другого формата, кроме как дату и время в азиатском формате. А значит вывести из этого поля ничего опасного нельзя в принципе. Так что все там ровно.
По поводу call_user_func() - у каждого свои тараканы))) У меня их тоже полно. Просто хотелось узнать аргументацию. Да. что-то в этом есть. Но вообще это не очень хорошая практика. Особенно если пишешь не только для себя любимого. Мне допустим читать сложнее, ибо непривычно. И тому, кто будет работать с проектом тоже будет достаточно печально.
Вообще все эти проблемы решаются одним простым действием - сменой редактора. Дрим - хорошая штука, но он плохо приспособлен к кодингу. Верстка- то да. А кодить лучше в специальных профильных редакторах. Там и с подсветкой нет проблем и с выводом функций. Допустим NetBeans.
Понимаю, привычки бросать трудно, но там столько возможностей, что через пару недель дрим будет страшно открывать.
По поводу call_user_func() - у каждого свои тараканы))) У меня их тоже полно. Просто хотелось узнать аргументацию. Да. что-то в этом есть. Но вообще это не очень хорошая практика. Особенно если пишешь не только для себя любимого. Мне допустим читать сложнее, ибо непривычно. И тому, кто будет работать с проектом тоже будет достаточно печально.
Вообще все эти проблемы решаются одним простым действием - сменой редактора. Дрим - хорошая штука, но он плохо приспособлен к кодингу. Верстка- то да. А кодить лучше в специальных профильных редакторах. Там и с подсветкой нет проблем и с выводом функций. Допустим NetBeans.
Понимаю, привычки бросать трудно, но там столько возможностей, что через пару недель дрим будет страшно открывать.
Спустя 19 минут, 22 секунды (18.09.2012 - 20:09) NierRa написал(а):
Цитата |
у каждого свои тараканы |
Я всегда задавался вопросом баг это или фича?

Качаю netBeans. Он универсальный или в нем только определенные языки поддерживаются? Интересует в частности С++
Спустя 9 часов, 22 минуты, 16 секунд (19.09.2012 - 05:31) twin написал(а):
Не подскажу, не помню. Я пользуюсь самодельным редактором)))
_____________
Задача на корректную обработку данных (мое решение)
http://eu.battle.net/sc2/ru/profile/2212951/1/IIIIIIIIIIII/